Why two hooks#
On-chain reads of encrypted values aren't free queries. FHEVM requires the contract to call FHE.allow(handle, msg.sender)to grant the caller ACL on the result, that's a tx. So the SDK exposes encrypted-view reads as useMutationhooks. Once the handle is in your hand, decrypting is a relayer round trip, a separate concern.
1. Grant yourself ACL#
// 1. Submit the encrypted-view tx. Contract grants ACL to msg.sender.
const getVested = useGetVestedAmount({ address: managerAddress });
getVested.mutate({
vestingId,
timestamp: Math.floor(Date.now() / 1000),
});
// getVested.data → { handle: "0x...", hash: "0x..." } when settled.2. Decrypt the handle#
// 2. Reactively decrypt the handle via the relayer.
const decrypted = useDecryptedHandle({
handle: getVested.data?.handle,
enabled: !!getVested.data?.handle,
});
// decrypted.data is the plaintext bigint once the relayer returns.
if (decrypted.isPending) return <span>Decrypting…</span>;
return <span>{decrypted.data?.toString()} ARI vested</span>;What goes wrong#
Decrypt fails with "Not authorized."The wallet signing the relayer request isn't the one that received the ACL grant in step 1. Verify you're using the same wallet across both phases.
Decrypt returns last tick's value. useGetVestedAmount takes a timestamp arg, pass the current second to force a fresh on-chain compute.