1. Provider tree#
WagmiProvider → QueryClientProvider → ZamaSDKProvider. Mount these in a "use client" file at the root of your app's layout. Order matters: wagmi's hooks need QueryClient; Zama's relayer needs wagmi's wallet state.
// app/providers.tsx
"use client";
import { WagmiProvider } from "wagmi";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { ZamaSDKProvider } from "@zama-fhe/react-sdk";
import { wagmiConfig } from "@/lib/wagmi";
const queryClient = new QueryClient();
export function Providers({ children }: { children: React.ReactNode }) {
return (
<WagmiProvider config={wagmiConfig}>
<QueryClientProvider client={queryClient}>
<ZamaSDKProvider>{children}</ZamaSDKProvider>
</QueryClientProvider>
</WagmiProvider>
);
}In app/layout.tsx, wrap {children} in <Providers>.
2. Use SDK hooks in client components#
Hooks live at @tokenops/sdk/<product>/react. Every hook is a TanStack Query primitive, mutations are useMutation, reads are useQuery. Use them like any other wagmi or viem hook.
// components/CreateVestingButton.tsx
"use client";
import { useZamaSDK } from "@zama-fhe/react-sdk";
import { useCreateVesting } from "@tokenops/sdk/fhe-vesting/react";
import type { Address } from "viem";
export function CreateVestingButton({
managerAddress,
recipient,
}: {
managerAddress: Address;
recipient: Address;
}) {
const zamaSDK = useZamaSDK();
const create = useCreateVesting({
address: managerAddress,
// Lazy factory: resolves the encryptor at submit time, not at mount.
encryptor: () => zamaSDK.relayer,
});
return (
<button
disabled={create.isPending}
onClick={() =>
create.mutate({
params: {
recipient,
startTimestamp: Math.floor(Date.now() / 1000),
endTimestamp: Math.floor(Date.now() / 1000) + 365 * 24 * 3600,
cliffSeconds: 0,
releaseIntervalSecs: 86_400,
timelockSeconds: 0,
initialUnlockBps: 0,
cliffAmountBps: 0,
isRevocable: false,
},
amount: 100_000n,
})
}
>
{create.isPending ? "Submitting…" : "Create vesting"}
</button>
);
}What server components can do#
Plenty, just not the encrypted writes. The headless client classes work fine on the server for reads: balance lookups, deployment metadata, vesting schedule shapes, address registry access. Anything that doesn't submit a tx is fair game in a server component or server action.