Ch 2: Contract Hooks
In this chapter, you'll build the React hooks that connect your UI to the ClownBeatdown contract. These hooks encapsulate all contract interaction logic so your components stay clean. Estimated time: ~15 minutes
Contract ABI setup
First, copy the compiled ABI from your contracts build output into the web package. After deploying (see Deploying), copy the ABI file:
mkdir -p packages/web/src/abis/contracts
cp packages/contracts/out/ClownBeatdown.sol/ClownBeatdown.json \
packages/web/src/abis/contracts/ClownBeatdown.jsonYou'll also need to add the deployed contract address and chain ID to the JSON file. After copying, edit the file to include address and chainId at the top level. The final structure should look like:
{
"address": "0xYourDeployedAddress",
"chainId": 31337,
"abi": [
{ "type": "constructor", "inputs": [...] },
{ "type": "function", "name": "hit", ... },
...
]
}You can find the deployed address in packages/contracts/broadcast/ClownBeatdown.s.sol/31337/run-latest.json under transactions[0].contractAddress.
Contract type definition
Create src/types/contract.ts:
useContract hook
This hook creates a shielded contract instance using seismic-react. Create src/hooks/useContract.ts:
The useShieldedContract hook from seismic-react returns a contract instance that supports both shielded writes and signed reads — the same interface you used in the CLI with getShieldedContract, but integrated with React's lifecycle.
useContractClient hook
This hook wraps the contract methods into callable functions with proper error handling. Create src/hooks/useContractClient.ts:
What's happening here?
Notice the different contract namespaces used for each method:
appContract().twrite.hit()andappContract().twrite.reset()— these are shielded write transactions. Thetwritenamespace sends a Seismic transaction (type 0x70) that encrypts calldata.appContract().read.rob()— this is a signed read. Thereadnamespace performs asigned_callthat proves the caller's identity to the contract, allowingonlyContributorto verify access. The result comes back asHexand is decoded withhexToString().appContract().tread.getClownStamina()— this is a transparent read. Thetreadnamespace performs a standardeth_callsince stamina is public state.
This distinction between twrite, read, and tread is the key difference from a standard Ethereum dApp.
Supporting components
Before building the game actions hook, create the helper components and hooks it depends on.
Explorer toast — Create src/components/chain/ExplorerToast.tsx:
Toast notifications — Create src/hooks/useToastNotifications.ts:
useGameActions hook
This hook orchestrates the game logic, managing state and coordinating contract calls with UI feedback. Create src/hooks/useGameActions.ts:
This hook manages the full game lifecycle:
fetchGameRounds— reads the current stamina from the contract viatread.getClownStamina()handleHit— sends a shielded write viatwrite.hit(), shows toast notifications with explorer links, waits for the receipt, increments punch count, and refetches staminahandleReset— validates the clown is KO, sends a shielded write viatwrite.reset(), clears punch count and rob result, and refetches staminahandleRob— performs a signed read viaread.rob()to decrypt and reveal a secret from the clown's poolresetGameState— clears the rob result and punch count when the round changes
Last updated

