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
- Create and connect a client.
- Know which encrypted type each value needs. It must match the Solidity parameter your contract declares, for example
externalEuint32againstexternalEuint64. - Know the address of the contract that will consume the inputs. You have to declare it before signing.
Basic usage
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.
Using the result in a transaction
The handle and its proof are a pair. In Solidity the proof parameter follows the handle it authenticates: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.
.execute().
The encryption flow
.execute() runs five sequential steps:
Creating the inputs
Use theEncryptable factory to build the items. Each function takes the plaintext value and an optional security zone.
There is also a generic form:
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
Encryptabletype.Encryptable.uint32(...)has to match theexternalEuint32your 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.