### Install the Relayer SDK CLI Source: https://github.com/zama-ai/relayer-sdk/blob/main/docs/cli.md Globally install the `@zama-fhe/relayer-sdk` package using npm to enable the CLI tool. Ensure Node.js is installed first. ```bash npm install -g @zama-fhe/relayer-sdk ``` -------------------------------- ### Complete Delegate Decryption Example Source: https://github.com/zama-ai/relayer-sdk/blob/main/docs/delegate-decrypt.md This example shows the full workflow for delegated decryption, from contract setup to final decryption. It requires Alice to authorize Bob as a delegate before Bob can decrypt data encrypted by Alice. Ensure you have ALICE_PRIVATE_KEY and BOB_PRIVATE_KEY defined. ```typescript import { ethers } from 'ethers'; import { createInstance, SepoliaConfig } from '@zama-fhe/relayer-sdk/node'; async function delegateDecryptExample() { // Setup provider and signers const provider = new ethers.JsonRpcProvider( 'https://ethereum-sepolia-rpc.publicnode.com', ); const aliceSigner = new ethers.Wallet(ALICE_PRIVATE_KEY, provider); const bobSigner = new ethers.Wallet(BOB_PRIVATE_KEY, provider); const aliceAddr = await aliceSigner.getAddress(); const bobAddr = await bobSigner.getAddress(); // Initialize FHEVM instance with Sepolia config const fhevmInstance = await createInstance({ ...SepoliaConfig, network: provider, }); // Contract setup const contractAddress = '0x...'; // Your deployed contract address const contract = new ethers.Contract( contractAddress, [ 'function initialize(uint32 value) external', 'function encryptedValue() public view returns (uint256)', ], aliceSigner, ); // Step 1: Alice initializes encrypted value const tx1 = await contract.initialize(123456); await tx1.wait(); // Step 2: Alice authorizes Bob as delegate const aclAddress = SepoliaConfig.aclContractAddress; const acl = new ethers.Contract( aclAddress, [ 'function delegateForUserDecryption(address delegate, address contractAddress, uint64 expirationDate) external', ], aliceSigner, ); const expirationDate = Math.floor(Date.now() / 1000) + 365 * 24 * 60 * 60; // 1 year const tx2 = await acl.delegateForUserDecryption( bobAddr, contractAddress, expirationDate, ); await tx2.wait(); // Step 3: Get encrypted handle and convert to hex const handleRaw = await contract.encryptedValue(); const handleHex = ethers.toBeHex(handleRaw, 32); // Step 4: Bob generates keypair const bobKeypair = fhevmInstance.generateKeypair(); // Step 5: Create EIP-712 message const extraData = '0x00'; const startTimestamp = Math.floor(Date.now() / 1000); const durationDays = 10; const eip712 = fhevmInstance.createDelegatedUserDecryptEIP712( bobKeypair.publicKey, [contractAddress], aliceAddr, startTimestamp, durationDays, extraData, ); // Step 6: Bob signs the message const signature = await bobSigner.signTypedData( eip712.domain, { DelegatedUserDecryptRequestVerification: eip712.types.DelegatedUserDecryptRequestVerification, }, eip712.message, ); // Step 7: Bob performs delegated decryption const results = await fhevmInstance.delegatedUserDecrypt( [{ handle: handleHex, contractAddress }], bobKeypair.privateKey, bobKeypair.publicKey, signature.replace('0x', ''), [contractAddress], aliceAddr, bobAddr, startTimestamp, durationDays, extraData, ); const decryptedValue = results[handleHex]; console.log('Decrypted value:', decryptedValue); // Output: 123457 (contract adds 1) } ``` -------------------------------- ### Encryption Usage Example with Async Options Source: https://github.com/zama-ai/relayer-sdk/blob/main/API_MIGRATION.md Demonstrates how to use the encrypt method with optional asynchronous parameters like timeout and an onProgress callback for real-time feedback. ```typescript const builder = instance.createEncryptedInput(contractAddress, userAddress); builder.add8(12); builder.add32(34); const result = await builder.encrypt({ timeout: 60000, onProgress: (args: RelayerInputProofProgressArgs) => { console.log(`${args.type}: ${args.elapsedMs}ms`); }, }); ``` -------------------------------- ### Verify CLI Installation Source: https://github.com/zama-ai/relayer-sdk/blob/main/docs/cli.md Access the CLI using the `relayer` command and verify the installation by exploring available commands. ```bash relayer help ``` -------------------------------- ### Install Relayer SDK with npm, Yarn, or pnpm Source: https://github.com/zama-ai/relayer-sdk/blob/main/README.md Use your preferred package manager to install the fhevm Relayer SDK and its dependencies. ```bash # Using npm npm install @zama-fhe/relayer-sdk # Using Yarn yarn add @zama-fhe/relayer-sdk # Using pnpm pnpm add @zama-fhe/relayer-sdk ``` -------------------------------- ### Create FHEVM Instance with Sepolia Configuration Source: https://github.com/zama-ai/relayer-sdk/blob/main/docs/initialization.md Initialize the FHEVM instance using the pre-defined `SepoliaConfig` object for simplified setup on the Sepolia testnet. Ensure the network RPC URL is correctly provided. ```typescript import { createInstance, SepoliaConfig } from '@zama-fhe/relayer-sdk'; const instance = await createInstance({ ...SepoliaConfig, network: 'https://ethereum-sepolia-rpc.publicnode.com', }); ``` -------------------------------- ### Create FHEVM Instance for Mainnet Source: https://github.com/zama-ai/relayer-sdk/blob/main/docs/initialization.md Initialize the FHEVM instance for Mainnet using `MainnetConfig`. This requires a Zama API key for authentication, which should be provided in the `auth` object. Ensure your API key is securely stored and accessed, for example, via environment variables. ```typescript import { createInstance, MainnetConfig } from '@zama-fhe/relayer-sdk'; const ZAMA_FHEVM_API_KEY = process.env.ZAMA_FHEVM_API_KEY; // Your Zama API key const instance = await createInstance({ ...MainnetConfig, network: 'https://ethereum-rpc.publicnode.com', // or your preferred Ethereum mainnet RPC auth: { __type: 'ApiKeyHeader', value: ZAMA_FHEVM_API_KEY }, }); ``` -------------------------------- ### Import SDK from Bundle Source: https://github.com/zama-ai/relayer-sdk/blob/main/docs/webapp.md Import necessary functions from the relayer SDK bundle if you have installed the package. ```javascript import { initSDK, createInstance, SepoliaConfig, } from '@zama-fhe/relayer-sdk/bundle'; ``` -------------------------------- ### Public Decryption Usage Example with Async Options Source: https://github.com/zama-ai/relayer-sdk/blob/main/API_MIGRATION.md Shows how to invoke the publicDecrypt method with optional asynchronous parameters including timeout, signal, onProgress callback, and authentication. ```typescript const result = await instance.publicDecrypt(handles, { timeout, //signal: abortController.signal, onProgress: (args: RelayerPublicDecryptProgressArgs) => { console.log(`${args.type}: ${args.elapsedMs}ms`); }, auth: { __type: 'ApiKeyHeader', value: zamaFhevmApiKey }, }); ``` -------------------------------- ### User Decryption Usage Example with Async Options Source: https://github.com/zama-ai/relayer-sdk/blob/main/API_MIGRATION.md Illustrates calling the userDecrypt method with various parameters including asynchronous options such as timeout, signal, onProgress callback, and authentication. ```typescript const result = await instance.userDecrypt( handleContractPairs, keypair.privateKey, keypair.publicKey, signature, contractAddresses, signer.address, startTimeStamp, durationDays, { timeout, //signal: abortController.signal, onProgress: (args: RelayerUserDecryptProgressArgs) => { console.log(`${args.type}: ${args.elapsedMs}ms`); }, auth: { __type: 'ApiKeyHeader', value: zamaFhevmApiKey }, }, ); ``` -------------------------------- ### Initialize Relayer SDK with API Key Source: https://github.com/zama-ai/relayer-sdk/blob/main/docs/mainnet-api-key.md Configure the Relayer SDK for mainnet usage by providing your API key during initialization. Ensure the API key is stored securely, for example, in environment variables. ```typescript import { createInstance, MainnetConfig } from '@zama-fhe/relayer-sdk'; const ZAMA_FHEVM_API_KEY = process.env.ZAMA_FHEVM_API_KEY; // Your Zama API key const instance = await createInstance({ ...MainnetConfig, network: 'https://ethereum-rpc.publicnode.com', // or your preferred Ethereum mainnet RPC auth: { __type: 'ApiKeyHeader', value: ZAMA_FHEVM_API_KEY }, }); ``` -------------------------------- ### Calling FHE Addition from Ethers Source: https://github.com/zama-ai/relayer-sdk/blob/main/docs/input.md Example of how to call the `add` function on a Solidity contract using the `ethers` library. It passes the ciphertext handles and the input proof obtained from the encryption process. ```js my_contract.add( ciphertexts.handles[0], ciphertexts.handles[1], ciphertexts.inputProof, ); ``` -------------------------------- ### Initialize SDK and Generate Keys Source: https://github.com/zama-ai/relayer-sdk/blob/main/e2e/servers/site/foo/browser.html Initializes the SDK, sets up TFHE parameters, generates client and public keys, and serializes them. Also generates and serializes CompactPkeCrs with different parameters. ```javascript async function initializeApp(protocolSDK) { const startTime = Date.now(); // Use the library await protocolSDK.initSDK(); const SERIALIZED_SIZE_LIMIT_PK = BigInt(1024 * 1024 * 512); const SERIALIZED_SIZE_LIMIT_CRS = BigInt(1024 * 1024 * 512); const tfhe = protocolSDK.tfhe; const block_params = new tfhe.ShortintParameters( tfhe.ShortintParametersName.PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128, ); const casting_params = new tfhe.ShortintCompactPublicKeyEncryptionParameters( tfhe.ShortintCompactPublicKeyEncryptionParametersName.V1_0_PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128, ); const config = tfhe.TfheConfigBuilder.default() .use_custom_parameters(block_params) .use_dedicated_compact_public_key_parameters(casting_params) .build(); const clientKey = tfhe.TfheClientKey.generate(config); const publicKey = tfhe.TfheCompactPublicKey.new(clientKey); const publicKeyBin = publicKey.safe_serialize(SERIALIZED_SIZE_LIMIT_PK); const privateKeyBin = clientKey.safe_serialize(SERIALIZED_SIZE_LIMIT_PK); await trace(publicKeyBin instanceof Uint8Array, startTime); await trace(publicKeyBin.length, startTime); await trace(privateKeyBin instanceof Uint8Array, startTime); await trace(privateKeyBin.length, startTime); const crs0 = tfhe.CompactPkeCrs.from_config(config, 4 * 32); const crs128 = crs0.safe_serialize(SERIALIZED_SIZE_LIMIT_CRS); await trace("crs128.length=" + crs128.length, startTime); const crs1 = tfhe.CompactPkeCrs.from_config(config, 4 * 64); const crs256 = crs1.safe_serialize(SERIALIZED_SIZE_LIMIT_CRS); await trace("crs256.length=" + crs256.length, startTime); const crs2 = tfhe.CompactPkeCrs.from_config(config, 4 * 128); const crs512 = crs2.safe_serialize(SERIALIZED_SIZE_LIMIT_CRS); await trace("crs512.length=" + crs512.length, startTime); const crs3 = tfhe.CompactPkeCrs.from_config(config, 4 * 256); const crs1024 = crs3.safe_serialize(SERIALIZED_SIZE_LIMIT_CRS); await trace("crs1024.length=" + crs1024.length, startTime); const crs4 = tfhe.CompactPkeCrs.from_config(config, 4 * 512); const crs2048 = crs4.safe_serialize(SERIALIZED_SIZE_LIMIT_CRS); await trace(`crs2048.length=${crs2048.length}`, startTime); } ``` -------------------------------- ### Initialize SDK using ESM CDN Source: https://github.com/zama-ai/relayer-sdk/blob/main/docs/webapp.md Initialize the SDK and create an instance using the ESM CDN, configuring the network with window.ethereum. ```javascript import { initSDK, createInstance, SepoliaConfig, } from 'https://cdn.zama.org/relayer-sdk-js/0.3.0-7/relayer-sdk-js.umd.cjs'; await initSDK(); const config = { ...SepoliaConfig, network: window.ethereum }; config.network = window.ethereum; const instance = await createInstance(config); ``` -------------------------------- ### Build Project Source: https://github.com/zama-ai/relayer-sdk/blob/main/HOW-TO.md Run the build command to compile the project after dependency updates. ```bash npm run build ``` -------------------------------- ### Initialize Relayer SDK with Bundled Version Source: https://github.com/zama-ai/relayer-sdk/blob/main/docs/webpack.md Use the prebundled version of the relayer SDK with a script tag and initialize it using window.fhevm.initSDK() and window.fhevm.createInstance(). ```javascript const start = async () => { await window.fhevm.initSDK(); // load wasm needed const config = { ...SepoliaConfig, network: window.ethereum }; config.network = window.ethereum; const instance = window.fhevm.createInstance(config).then((instance) => { console.log(instance); }); }; ``` -------------------------------- ### Initialize Application with UMD Library Source: https://github.com/zama-ai/relayer-sdk/blob/main/e2e/servers/site/foo/browser.html Initializes the application by loading the UMD library and then calling an initialization function with the loaded library. ```javascript // The protocol-sdk is served by localhost:5173 const umdUrl = 'http://localhost:5173/libs/relayer-sdk-js/relayer-sdk-js.umd.cjs'; const umdLibname = 'relayerSDK'; // The relayer-sdk is served by localhost:5174 // const umdUrl = 'http://localhost:5174/relayer-sdk-js/relayer-sdk-js.umd.cjs'; // const umdLibname = 'relayerSDK'; loadUMD(umdUrl, umdLibname) .then(library => { console.log("UMD loaded and ready!"); console.log("Library:", library); // Initialize your app initializeApp(library); }) .catch(error => { console.error("Error loading UMD:", error); }); ``` -------------------------------- ### Load WASM with initSDK Source: https://github.com/zama-ai/relayer-sdk/blob/main/docs/webapp.md Initialize the relayer SDK by loading the necessary WASM files before proceeding. ```javascript import { initSDK } from '@zama-fhe/relayer-sdk/bundle'; const init = async () => { await initSDK(); // Load needed WASM }; ``` -------------------------------- ### Create Relayer SDK Instance Source: https://github.com/zama-ai/relayer-sdk/blob/main/docs/webapp.md After loading the WASM, create an instance of the relayer SDK using the Sepolia configuration and the user's Ethereum network. ```javascript import { initSDK, createInstance, SepoliaConfig, } from '@zama-fhe/relayer-sdk/bundle'; const init = async () => { await initSDK(); // Load FHE const config = { ...SepoliaConfig, network: window.ethereum }; return createInstance(config); }; init().then((instance) => { console.log(instance); }); ``` -------------------------------- ### Run Tests Source: https://github.com/zama-ai/relayer-sdk/blob/main/HOW-TO.md Execute the test suite to verify the integrity of the project after dependency updates. ```bash npm test ``` -------------------------------- ### Import SDK from npm Package Source: https://github.com/zama-ai/relayer-sdk/blob/main/docs/webapp.md Import the relayer SDK from the npm package. Ensure your package.json has '"type": "module"' or use '@zama-fhe/relayer-sdk/web' for CommonJS. ```javascript import { initSDK, createInstance, SepoliaConfig } from '@zama-fhe/relayer-sdk'; ``` -------------------------------- ### Create FHEVM Instance with Full Configuration Source: https://github.com/zama-ai/relayer-sdk/blob/main/docs/initialization.md Instantiate the FHEVM instance with all required contract addresses and chain configurations. This method provides explicit control over each parameter. ```typescript import { createInstance } from '@zama-fhe/relayer-sdk'; const instance = await createInstance({ // ACL_CONTRACT_ADDRESS (FHEVM Host chain) aclContractAddress: '0xf0Ffdc93b7E186bC2f8CB3dAA75D86d1930A433D', // KMS_VERIFIER_CONTRACT_ADDRESS (FHEVM Host chain) kmsContractAddress: '0xbE0E383937d564D7FF0BC3b46c51f0bF8d5C311A', // INPUT_VERIFIER_CONTRACT_ADDRESS (FHEVM Host chain) inputVerifierContractAddress: '0xBBC1fFCdc7C316aAAd72E807D9b0272BE8F84DA0', // DECRYPTION_ADDRESS (Gateway chain) verifyingContractAddressDecryption: '0x5D8BD78e2ea6bbE41f26dFe9fdaEAa349e077478', // INPUT_VERIFICATION_ADDRESS (Gateway chain) verifyingContractAddressInputVerification: '0x483b9dE06E4E4C7D35CCf5837A1668487406D955', // FHEVM Host chain id chainId: 11155111, // Gateway chain id gatewayChainId: 10901, // RPC provider to host chain (or Eip1193Provider) network: 'https://ethereum-sepolia-rpc.publicnode.com', // Relayer URL relayerUrl: 'https://relayer.testnet.zama.org', }); ``` -------------------------------- ### Configure Network with Eip1193Provider Instance Source: https://github.com/zama-ai/relayer-sdk/blob/main/docs/initialization.md Integrate with browser wallets like MetaMask by providing an `Eip1193Provider` instance to the `network` property. This allows the SDK to use the wallet's connection to the blockchain. ```typescript import { createInstance, SepoliaConfig } from '@zama-fhe/relayer-sdk'; // Using window.ethereum from MetaMask or other browser wallets const instance = await createInstance({ ...SepoliaConfig, network: window.ethereum, // Eip1193Provider }); ``` -------------------------------- ### Create and Encrypt Inputs for FHEVM Source: https://github.com/zama-ai/relayer-sdk/blob/main/docs/input.md Use this to create a buffer for values, add them with their data types, and then encrypt them to generate ciphertext handles and a proof of knowledge. This process prepares inputs for on-chain FHE operations. ```ts const buffer = instance.createEncryptedInput( // The address of the contract allowed to interact with the "fresh" ciphertexts contractAddress, // The address of the entity allowed to import ciphertexts to the contract at `contractAddress` userAddress, ); // We add the values with associated data-type method buffer.add64(BigInt(23393893233)); buffer.add64(BigInt(1)); // buffer.addBool(false); // buffer.add8(BigInt(43)); // buffer.add16(BigInt(87)); // buffer.add32(BigInt(2339389323)); // buffer.add128(BigInt(233938932390)); // buffer.addAddress('0xa5e1defb98EFe38EBb2D958CEe052410247F4c80'); // buffer.add256(BigInt('2339389323922393930')); // This will encrypt the values, generate a proof of knowledge for it, and then upload the ciphertexts using the relayer. // This action will return the list of ciphertext handles. const ciphertexts = await buffer.encrypt(); ``` -------------------------------- ### Include UMD CDN for Relayer SDK Source: https://github.com/zama-ai/relayer-sdk/blob/main/docs/webapp.md Include the UMD bundle from the Zama CDN at the top of your HTML to use the relayer SDK. ```html ``` -------------------------------- ### Trace Execution and Display Source: https://github.com/zama-ai/relayer-sdk/blob/main/e2e/servers/site/foo/browser.html Logs messages to the DOM with execution timestamps and introduces a small delay for visual tracing. ```javascript async function trace(str, startTime) { const p = document.createElement('p'); p.textContent = `\[${Date.now() - startTime}ms\] ${str}`; document.body.appendChild(p); // repaint p.offsetHeight; await sleep(200); } ``` -------------------------------- ### Generate Keys Source: https://github.com/zama-ai/relayer-sdk/blob/main/HOW-TO.md Execute this script to update keys, which may be necessary for changes in crypto-parameters or serialization. ```bash ./generateKeys.js ``` -------------------------------- ### Webpack Fallbacks for Node.js Core Modules Source: https://github.com/zama-ai/relayer-sdk/blob/main/docs/webpack.md Configure Webpack fallbacks for Node.js core modules like buffer, crypto, stream, and path to ensure browser compatibility. ```javascript resolve: { fallback: { buffer: require.resolve('buffer/'), crypto: require.resolve('crypto-browserify'), stream: require.resolve('stream-browserify'), path: require.resolve('path-browserify'), }, } ``` -------------------------------- ### Regenerate package-lock.json Source: https://github.com/zama-ai/relayer-sdk/blob/main/HOW-TO.md Run this command to update the package-lock.json file after modifying package.json. ```bash npm install ``` -------------------------------- ### Solidity Contract for FHE Addition Source: https://github.com/zama-ai/relayer-sdk/blob/main/docs/input.md This Solidity contract snippet demonstrates how to implement an `add` function that utilizes FHE operations. It takes two external ciphertexts and a proof, then returns the encrypted sum. ```solidity contract MyContract { ... function add( externalEuint64 a, externalEuint64 b, bytes calldata proof ) public virtual returns (euint64) { return FHE.add(FHE.fromExternal(a, proof), FHE.fromExternal(b, proof)) } } ``` -------------------------------- ### Encrypt Integer and Boolean Data Source: https://github.com/zama-ai/relayer-sdk/blob/main/docs/cli.md Encrypt a 64-bit integer and a boolean for a specific contract and user address. The data is appended with its type (e.g., `:64` for 64-bit integers, `:1` for booleans). ```bash relayer encrypt 0x8Fdb26641d14a80FCCBE87BF455338Dd9C539a50 0xa5e1defb98EFe38EBb2D958CEe052410247F4c80 71721075:64 1:1 ``` -------------------------------- ### Load UMD Script Dynamically Source: https://github.com/zama-ai/relayer-sdk/blob/main/e2e/servers/site/foo/browser.html Loads a UMD script from a given URL and resolves with the global variable name specified. Handles cases where the script might already be loaded. ```javascript function loadUMD(src, globalName) { return new Promise((resolve, reject) => { // Check if already loaded if (window[globalName]) { resolve(window[globalName]); return; } const script = document.createElement('script'); script.src = src; script.onload = () => { if (window[globalName]) { resolve(window[globalName]); } else { reject(new Error(`Global ${globalName} not found after loading`)); } }; script.onerror = () => reject(new Error(`Failed to load ${src}`)); document.head.appendChild(script); }); } ``` -------------------------------- ### Async Options Types for Relayer SDK Source: https://github.com/zama-ai/relayer-sdk/blob/main/API_MIGRATION.md TypeScript type definitions for asynchronous operation options, including authentication, debugging, signals, timeouts, and progress callbacks for different relayer SDK methods. ```typescript type RelayerInputProofOptionsType = { auth?: Auth | undefined; debug?: boolean | undefined; signal?: AbortSignal | undefined; timeout?: number | undefined; onProgress?: ((args: RelayerInputProofProgressArgs) => void) | undefined; }; type RelayerPublicDecryptOptionsType = { auth?: Auth | undefined; debug?: boolean | undefined; signal?: AbortSignal | undefined; timeout?: number | undefined; onProgress?: ((args: RelayerPublicDecryptProgressArgs) => void) | undefined; }; type RelayerUserDecryptOptionsType = { auth?: Auth | undefined; debug?: boolean | undefined; signal?: AbortSignal | undefined; timeout?: number | undefined; onProgress?: ((args: RelayerUserDecryptProgressArgs) => void) | undefined; }; ``` -------------------------------- ### Webpack Fallback for 'tfhe_bg.wasm' Source: https://github.com/zama-ai/relayer-sdk/blob/main/docs/webpack.md Add a resolve fallback configuration in webpack.config.js to resolve 'tfhe_bg.wasm' when it cannot be found. ```javascript resolve: { fallback: { 'tfhe_bg.wasm': require.resolve('tfhe/tfhe_bg.wasm'), }, } ``` -------------------------------- ### Async API Signatures for Relayer SDK Source: https://github.com/zama-ai/relayer-sdk/blob/main/API_MIGRATION.md Defines the updated TypeScript signatures for the encrypt, publicDecrypt, and userDecrypt methods in the relayer-sdk, now supporting optional asynchronous options. ```typescript encrypt: (options?: RelayerInputProofOptionsType) => Promise<{ handles: Uint8Array[]; inputProof: Uint8Array; }>; publicDecrypt: ( handles: (string | Uint8Array)[], options?: RelayerPublicDecryptOptionsType, ) => Promise; userDecrypt: ( handles: HandleContractPair[], privateKey: string, publicKey: string, signature: string, contractAddresses: string[], userAddress: string, startTimestamp: string | number, durationDays: string | number, options?: RelayerUserDecryptOptionsType, ) => Promise; ``` -------------------------------- ### Decrypting Ciphertext Handles Source: https://github.com/zama-ai/relayer-sdk/blob/main/docs/delegate-decrypt.md Use `delegatedUserDecrypt` to decrypt multiple ciphertext handles. Ensure handles are formatted as 32-byte hex strings. The total bit length of all ciphertexts must not exceed 2048 bits. ```typescript // Convert handle to proper hex format (32 bytes = 0x + 64 hex chars) const handleHex = ethers.toBeHex(ciphertextHandle, 32); const handleContractPairs = [ { handle: handleHex, contractAddress: contractAddress, }, ]; const result = await instance.delegatedUserDecrypt( handleContractPairs, keypair.privateKey, keypair.publicKey, signature.replace('0x', ''), contractAddresses, delegatorAddress, delegateAddress, startTimestamp, durationDays, extraData, ); // result maps each handle to its decrypted value const decryptedBalance = result[handleHex]; ``` -------------------------------- ### Create EIP-712 Message for Delegate Decryption Source: https://github.com/zama-ai/relayer-sdk/blob/main/docs/delegate-decrypt.md Generates the EIP-712 typed data structure required for delegate decryption. Ensure you have an initialized FhevmInstance and the necessary contract and delegator addresses. The `extraData` parameter is mandatory; use '0x00' as a default. ```typescript import { createInstance } from '@zama-fhe/relayer-sdk/node'; // instance: FhevmInstance (see initialization guide) // delegatorAddress: the data owner's address // contractAddress: the contract holding the encrypted value const keypair = instance.generateKeypair(); // For production/testnet: use '0x00' as default extraData // Future SDK versions may include getExtraData() for context-aware decryption const extraData = '0x00'; const contractAddresses = [contractAddress]; const startTimestamp = Math.floor(Date.now() / 1000); const durationDays = 10; const eip712 = instance.createDelegatedUserDecryptEIP712( keypair.publicKey, contractAddresses, delegatorAddress, startTimestamp, durationDays, extraData, ); ``` -------------------------------- ### Retrieve Encrypted Balance Handle Source: https://github.com/zama-ai/relayer-sdk/blob/main/docs/user-decryption.md Implement a view function in your Solidity smart contract to retrieve a user's encrypted balance handle. This handle is an identifier for the underlying ciphertext stored on the blockchain. ```solidity import "@fhevm/solidity/lib/FHE.sol"; contract ConfidentialERC20 { ... function balanceOf(account address) public view returns (euint64) { return balances[msg.sender]; } ... } ``` -------------------------------- ### createDelegatedUserDecryptEIP712 Source: https://github.com/zama-ai/relayer-sdk/blob/main/docs/delegate-decrypt.md Creates the EIP-712 typed data structure required for delegate decryption. This structure is used to generate the signature needed for the `delegatedUserDecrypt` call. ```APIDOC ## createDelegatedUserDecryptEIP712 ### Description Creates the EIP-712 typed data structure for delegate decryption. ### Method (Not specified, likely a SDK method call) ### Parameters #### Path Parameters (None specified) #### Query Parameters (None specified) #### Request Body - **publicKey** (string) - Required - The delegate's NaCl public key from `generateKeypair()` - **contractAddresses** (string[]) - Required - Contract addresses holding the encrypted values (max 10) - **delegatorAddress** (string) - Required - The data owner's address (must have ACL permission) - **startTimestamp** (number) - Required - Unix timestamp for when the permit becomes valid - **durationDays** (number) - Required - How many days the permit remains valid (1–365) - **extraData** (BytesHex) - Required - KMS context from `getExtraData()` ### Request Example (No example provided in source) ### Response #### Success Response - **(Implicit)** `KmsDelegatedUserDecryptEIP712Type` — the complete EIP-712 object with `domain`, `types`, and `message` fields. #### Response Example (No example provided in source) ``` -------------------------------- ### Granting ACL Permissions in Solidity Source: https://github.com/zama-ai/relayer-sdk/blob/main/docs/delegate-decrypt.md Use FHE.allow() and FHE.allowThis() in your Solidity contract to grant ACL permissions to the delegator and the contract itself, which is necessary for decryption. ```solidity import {FHE, euint64} from "@fhevm/solidity/lib/FHE.sol"; contract ConfidentialERC20 { mapping(address => euint64) internal balances; function transfer(address to, euint64 amount) public { // ... transfer logic ... FHE.allowThis(balances[to]); // required for decryption to work FHE.allow(balances[to], to); // grants ACL to the data owner (delegator) } } ``` -------------------------------- ### Registering Delegation with ACL Contract (JavaScript) Source: https://github.com/zama-ai/relayer-sdk/blob/main/docs/delegate-decrypt.md Authorize a delegate for user decryption by calling delegateForUserDecryption on the ACL contract. This registers the delegation on-chain with an expiration date. Ensure you use the correct ACL contract address for your chain. ```javascript import { ethers } from 'ethers'; // The ACL contract address (check your chain's ZamaConfig for the correct address) const ACL_ADDRESS = '0x...'; // chain-specific ACL address const ACL_ABI = [ 'function delegateForUserDecryption(address delegate, address contractAddress, uint64 expirationDate) external', ]; // delegatorSigner: the delegator's (data owner's) ethers Signer const acl = new ethers.Contract(ACL_ADDRESS, ACL_ABI, delegatorSigner); // Authorize the delegate for 1 year const expirationDate = Math.floor(Date.now() / 1000) + 365 * 24 * 60 * 60; const tx = await acl.delegateForUserDecryption( delegateAddress, contractAddress, expirationDate, ); await tx.wait(); ``` -------------------------------- ### Perform Client-Side User Decryption Source: https://github.com/zama-ai/relayer-sdk/blob/main/docs/user-decryption.md Use the `@zama-fhe/relayer-sdk` to perform user decryption client-side. This function takes a list of ciphertext handles and re-encrypts them with the user's public key, requiring a signature for verification. ```typescript // instance: [`FhevmInstance`] from `zama-fhe/relayer-sdk` // signer: [`Signer`] from ethers (could a [`Wallet`]) // ciphertextHandle: [`string`] // contractAddress: [`string`] const keypair = instance.generateKeypair(); // userDecrypt can take a batch of handles (with their corresponding contract addresses). // In this example we only pass one handle. const handleContractPairs = [ { handle: ciphertextHandle, contractAddress: contractAddress, }, ]; const startTimeStamp = Math.floor(Date.now() / 1000).toString(); const durationDays = '10'; // String for consistency const contractAddresses = [contractAddress]; const eip712 = instance.createEIP712( keypair.publicKey, contractAddresses, startTimeStamp, durationDays, ); const signature = await signer.signTypedData( eip712.domain, { UserDecryptRequestVerification: eip712.types.UserDecryptRequestVerification, }, eip712.message, ); const result = await instance.userDecrypt( handleContractPairs, keypair.privateKey, keypair.publicKey, signature.replace('0x', ''), contractAddresses, signer.address, startTimeStamp, durationDays, ); // result maps each handle to its decrypted value const decryptedValue = result[ciphertextHandle]; ``` -------------------------------- ### Sign EIP-712 Message as Delegate Source: https://github.com/zama-ai/relayer-sdk/blob/main/docs/delegate-decrypt.md Signs the EIP-712 message generated for delegate decryption using the delegate's ethers Signer. This action authenticates the delegate's authorization for the decryption request. ```typescript // delegateSigner: the delegate's ethers Signer const signature = await delegateSigner.signTypedData( eip712.domain, { DelegatedUserDecryptRequestVerification: eip712.types.DelegatedUserDecryptRequestVerification, }, eip712.message, ); ``` -------------------------------- ### Sleep Utility Function Source: https://github.com/zama-ai/relayer-sdk/blob/main/e2e/servers/site/foo/browser.html A simple utility function to pause execution for a specified duration. ```javascript const sleep = ms => new Promise(resolve => setTimeout(resolve, ms)); ``` -------------------------------- ### delegatedUserDecrypt Source: https://github.com/zama-ai/relayer-sdk/blob/main/docs/delegate-decrypt.md Performs the delegate decryption request through the Relayer. It takes handle-contract pairs, cryptographic keys, signature, and other relevant details to decrypt values. ```APIDOC ## delegatedUserDecrypt ### Description Performs the delegate decryption request through the Relayer. ### Method (Not specified, likely a SDK method call) ### Parameters #### Path Parameters (None specified) #### Query Parameters (None specified) #### Request Body - **handleContractPairs** (HandleContractPair[]) - Required - Array of `{ handle, contractAddress }` pairs to decrypt - **privateKey** (string) - Required - The delegate's NaCl private key from `generateKeypair()` - **publicKey** (string) - Required - The delegate's NaCl public key from `generateKeypair()` - **signature** (string) - Required - EIP-712 signature from the delegate (without `0x` prefix) - **contractAddresses** (string[]) - Required - Same contract addresses used in the EIP-712 message - **delegatorAddress** (string) - Required - The data owner's address - **delegateAddress** (string) - Required - The delegate's address (the signer) - **startTimestamp** (number) - Required - Same timestamp used in the EIP-712 message - **durationDays** (number) - Required - Same duration used in the EIP-712 message - **extraData** (BytesHex) - Required - Same `extraData` used in the EIP-712 message - **options** (RelayerUserDecryptOptionsType) - Optional - Request options (e.g., timeout) ### Request Example (No example provided in source) ### Response #### Success Response - **(Implicit)** A record mapping each handle (`0x${string}`) to its decrypted value (`bigint`, `boolean`, or `0x${string}`). #### Response Example (No example provided in source) ``` -------------------------------- ### Perform Public Decryption via HTTP Source: https://github.com/zama-ai/relayer-sdk/blob/main/docs/public-decryption.md Use this snippet to decrypt a list of ciphertext handles using the Relayer's public decrypt endpoint. Ensure the total bit length of ciphertexts does not exceed 2048 bits. The results object contains decrypted clear values and other related data. ```typescript // A list of ciphertexts handles to decrypt const handles = [ '0x830a61b343d2f3de67ec59cb18961fd086085c1c73ff0000000000aa36a70000', '0x98ee526413903d4613feedb9c8fa44fe3f4ed0dd00ff0000000000aa36a70400', '0xb837a645c9672e7588d49c5c43f4759a63447ea581ff0000000000aa36a70700', ]; // The list of decrypted values // results = { // clearValues: { // '0x830a61b343d2f3de67ec59cb18961fd086085c1c73ff0000000000aa36a70000': true, // '0x98ee526413903d4613feedb9c8fa44fe3f4ed0dd00ff0000000000aa36a70400': 242n, // '0xb837a645c9672e7588d49c5c43f4759a63447ea581ff0000000000aa36a70700': '0xfC4382C084fCA3f4fB07c3BCDA906C01797595a8' // } // abiEncodedClearValues: '0x.....' // decryptionProof: '0x.....' // } const results: PublicDecryptResults = instance.publicDecrypt(handles); ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.