Skip to main content
encryptInputs encrypts plaintext values into FHE ciphertexts you can pass into a confidential contract call. Values must be encrypted before they go onchain, or there is nothing confidential about them. One call produces one batch: a ciphertext handle for each value, plus a single signature covering the whole batch.

Prerequisites

  1. Create and connect a client.
  2. Know which encrypted type each value needs. It must match the Solidity parameter your contract declares, for example externalEuint32 against externalEuint64.
  3. Know the address of the contract that will consume the inputs. You have to declare it before signing.

Basic usage

The result holds one handle per input, in the order you passed them, followed by the batch signature. It has inputs.length + 1 elements, so code that assumes the result matches the input count is off by one.

Declaring the consuming contract

setConsumingContract is required. The verifier binds the target contract into the signed digest, so a batch signed for one contract cannot be replayed into another. Omitting it is a compile error in TypeScript: encryptInputs() returns a builder with no execute() method, and you get Property 'execute' does not exist on type 'EncryptInputsBuilderUnset'. JavaScript callers get no type check and hit a ConsumingContractUninitialized throw instead.
The consuming contract is the contract that runs FHE.asEuint*, which is not always the contract you call. If your app calls vault.deposit(...) and the vault is what converts the value, the consuming contract is the vault. Naming the wrong one compiles, typechecks, and reverts at runtime when the digest is recomputed onchain. Trace the value to the FHE.asEuint* call and use that address.

Using the result in a transaction

The handle and its proof are a pair. In Solidity the proof parameter follows the handle it authenticates:
For more than one encrypted value, the handles stay adjacent and share the one signature:
The signature does not have to be the last parameter, and encrypted parameters must be adjacent to each other because they share one signature. See migrating to 0.7 for the Solidity side.

Builder API

.setConsumingContract(address) (required)

The contract that will pass these values into FHE.asEuint*. Returns the builder that has execute().

.execute() (required, call last)

Runs the encryption pipeline and returns the handles followed by the batch signature.

.setAccount(address) (optional)

Override the address that owns the encrypted inputs. Only that address can use them onchain. Defaults to the connected wallet account.

.setChainId(chainId) (optional)

Override the chain the inputs will be used on. Defaults to the connected chain.

.setSecurityZone(zone) (optional)

Override the security zone the batch is encrypted under. Defaults to zone 0.

.setUseWorker(boolean) (optional)

When true, the default, ZK proof generation runs in a Web Worker so it does not block the main thread. No effect in Node.js.

.onStep(callback) (optional)

Fires at the start and end of each encryption step, which is useful for a progress indicator.
Setters can be called in any order, as long as they come before .execute().

The encryption flow

.execute() runs five sequential steps:

Creating the inputs

Use the Encryptable factory to build the items. Each function takes the plaintext value and an optional security zone. There is also a generic form:
A single encryptInputs call may encrypt at most 2048 bits of plaintext in total. Going over throws ZkPackFailed.

What replaced the per-item types

0.7 removed the per-item input structs. EncryptedItemInput, EncryptedUint64Input, and the rest of that family no longer exist, and neither does asHashPlusProof(), because its output is what execute() always returns now. A value that used to be one of those types is now a plain hash, typed `0x${string}`. The whole result is readonly `0x${string}`[].
These also break on your own helpers. A fixture typed (encAmount: EncryptedUint64Input) fails at its own definition, not at the call site. Spread the pair instead, or infer it with Awaited<ReturnType<typeof encryptAmount>>.

Common pitfalls

  • Forgetting the consuming contract, or naming the contract you call rather than the one that converts the value. The second one fails at runtime, not at compile time.
  • Destructuring the wrong length. The result carries a trailing signature, so a wrong-length destructure typechecks and then fails at runtime.
  • Wrong Encryptable type. Encryptable.uint32(...) has to match the externalEuint32 your function declares.
  • Wrong account or chain. Inputs are authorized for one account and chain. Overriding either can make them unusable for the transaction you intended.
  • Reusing one encryption against two contracts. Not possible with a single batch, because the signature binds to one consuming contract. Encrypt once per target.
  • Bit limit exceeded. At most 2048 bits per call, otherwise ZkPackFailed.