Concept · Encrypted handles

Encrypted inputs + handles

Three types wrap FHE state at the SDK boundary. Knowing which is which removes a class of misuse — passing an EncryptedInput where the contract wants a handle, or trying to decrypt a write proof.

EncryptedInput — what you submit#

An EncryptedInput is a discriminated union: { type: "euint64", value: bigint }, { type: "euint128", value: bigint }, and so on. The SDK turns this into a ciphertext + Zama proof bundle just before the tx submits, via the injected encryptor.

You usually never see EncryptedInput directly — write hooks like useCreateVesting take a { amount: bigint, ... } arg and wrap it for you. The type is exposed for two cases: batch encryption (where you build an N-input proof in one round-trip) and bring-your-own relayer paths.

EncryptedHandle — what lives on chain#

An EncryptedHandle is a bytes32 string. It's what the contract stores in place of a cleartext uint64 / uint128. The SDK types it as a branded Hex string so it doesn't collide with regular tx hashes or addresses.

Handles flow OUT of read hooks (encrypted views) and INTO write hooks (transfers, disperse, splits). The handle itself reveals nothing — it's just a pointer into the coprocessor's ciphertext storage.

EncryptedViewResult — what an FHE read returns#

Some "reads" are actually mutations because the contract has to call FHE.allow on each access to grant ACL to the caller. useGetVestedAmount, useGetClaimableAmount, and their admin variants all return { handle, hash }:

  • handleis the encrypted result you'll decrypt
  • hash is the tx hash that granted you ACL

Pair the handle with useDecryptedHandle to get the plaintext via the connected wallet's signature.

See also