跳到主要内容

useWriteContract

Hook to write to smart contracts with automatic encryption of input parameters.

Usage​

import { useWriteContract } from '@fhevm/sdk';

function TransferButton() {
const { write, isLoading, isSuccess } = useWriteContract({
address: '0x123...',
abi: tokenAbi,
});

const handleTransfer = async () => {
await write({
functionName: 'confidentialTransfer',
args: [recipientAddress, 100n],
});
};

return (
<button onClick={handleTransfer} disabled={isLoading}>
{isLoading ? 'Transferring...' : 'Transfer'}
</button>
);
}

Parameters​

type UseWriteContractParameters<TAbi extends Abi = Abi> = {
address?: `0x${string}`;
abi?: TAbi;
name?: string;
};
ParameterTypeDescription
address0x${string}Contract address
abiAbiContract ABI
namestringContract name from config

Write Arguments​

type WriteContractArgs = {
functionName: string;
args?: any[];
value?: bigint;
gasLimit?: bigint;
};
ParameterTypeDescription
functionNamestringFunction to call
argsany[]Function arguments (auto-encrypted)
valuebigintETH value to send
gasLimitbigintGas limit

Return Value​

type UseWriteContractReturnType = {
write: (args: WriteContractArgs) => Promise<TransactionReceipt | undefined>;
writeAsync: (args: WriteContractArgs) => Promise<TransactionReceipt | undefined>;
data: TransactionReceipt | undefined;
isLoading: boolean;
isSuccess: boolean;
isError: boolean;
error: Error | null;
reset: () => void;
};
PropertyTypeDescription
writeFunctionWrite function (catches errors)
writeAsyncFunctionWrite function (throws errors)
dataTransactionReceipt | undefinedTransaction receipt
isLoadingbooleanTransaction in progress
isSuccessbooleanTransaction succeeded
isErrorbooleanTransaction failed
errorError | nullError object
resetFunctionReset state

Examples​

Basic Write​

function BasicWrite() {
const { write, isLoading } = useWriteContract({
address: '0x123...',
abi: counterAbi,
});

return (
<button
onClick={() => write({ functionName: 'increment' })}
disabled={isLoading}
>
Increment
</button>
);
}

With Arguments​

function WithArgs() {
const { write, isLoading } = useWriteContract({
address: '0x123...',
abi: tokenAbi,
});

const transfer = () => {
write({
functionName: 'transfer',
args: [recipientAddress, 1000n],
});
};

return (
<button onClick={transfer} disabled={isLoading}>
Transfer
</button>
);
}

Encrypted Arguments​

Arguments are automatically encrypted based on ABI:

function EncryptedTransfer() {
const { write } = useWriteContract({
address: '0x123...',
abi: encryptedTokenAbi, // Has externalEuint64 types
});

const transfer = () => {
write({
functionName: 'confidentialTransfer',
// amount is automatically encrypted if ABI specifies externalEuint64
args: [recipientAddress, 100n],
});
};

return <button onClick={transfer}>Transfer</button>;
}

With ETH Value​

function PayableFunction() {
const { write } = useWriteContract({
address: '0x123...',
abi: contractAbi,
});

const deposit = () => {
write({
functionName: 'deposit',
value: ethers.parseEther('1.0'), // Send 1 ETH
});
};

return <button onClick={deposit}>Deposit 1 ETH</button>;
}

Custom Gas Limit​

function CustomGas() {
const { write } = useWriteContract({
address: '0x123...',
abi: contractAbi,
});

const execute = () => {
write({
functionName: 'complexOperation',
gasLimit: 500000n, // Custom gas limit
});
};

return <button onClick={execute}>Execute</button>;
}

Async Write with Error Handling​

function AsyncWrite() {
const { writeAsync, isLoading, error } = useWriteContract({
address: '0x123...',
abi: tokenAbi,
});

const handleTransfer = async () => {
try {
const receipt = await writeAsync({
functionName: 'transfer',
args: [recipientAddress, 100n],
});

console.log('Transaction confirmed:', receipt.transactionHash);
alert('Transfer successful!');
} catch (err) {
console.error('Transfer failed:', err);
alert('Transfer failed: ' + err.message);
}
};

return (
<div>
<button onClick={handleTransfer} disabled={isLoading}>
Transfer
</button>
{error && <div className="error">{error.message}</div>}
</div>
);
}

Success Callback​

function WithSuccess() {
const { write, isSuccess, data } = useWriteContract({
address: '0x123...',
abi: tokenAbi,
});

useEffect(() => {
if (isSuccess && data) {
console.log('Transaction hash:', data.transactionHash);
console.log('Block number:', data.blockNumber);
alert('Transaction successful!');
}
}, [isSuccess, data]);

return (
<button onClick={() => write({ functionName: 'transfer', args: [...] })}>
Transfer
</button>
);
}

Reset State​

function WithReset() {
const { write, isSuccess, isError, reset } = useWriteContract({
address: '0x123...',
abi: tokenAbi,
});

return (
<div>
<button onClick={() => write({ functionName: 'transfer', args: [...] })}>
Transfer
</button>

{isSuccess && (
<div>
Success! <button onClick={reset}>Reset</button>
</div>
)}

{isError && (
<div>
Error! <button onClick={reset}>Try Again</button>
</div>
)}
</div>
);
}

Named Contract​

function NamedContract() {
const { write } = useWriteContract({
name: 'myToken', // From config
});

return (
<button onClick={() => write({ functionName: 'approve', args: [...] })}>
Approve
</button>
);
}

TypeScript Support​

import type { MyTokenAbi } from './types';

function TypedWrite() {
const { write } = useWriteContract<MyTokenAbi>({
address: '0x123...',
abi: myTokenAbi,
});

const handleTransfer = () => {
write({
functionName: 'transfer', // Autocomplete works!
args: [recipient, amount], // Type-checked!
});
};

return <button onClick={handleTransfer}>Transfer</button>;
}

Automatic Encryption​

Detected Types​

The hook automatically encrypts arguments with these ABI types:

  • externalEuint8, externalEuint16, externalEuint32, externalEuint64, externalEuint128, externalEuint256
  • externalEbool
  • externalEaddress
  • euint8, euint16, euint32, euint64, euint128, euint256

Example ABI​

const tokenAbi = [
{
name: 'confidentialTransfer',
type: 'function',
inputs: [
{ name: 'to', type: 'address', internalType: 'address' },
{ name: 'amount', type: 'bytes32', internalType: 'externalEuint64' }, // Auto-encrypted
{ name: 'inputProof', type: 'bytes', internalType: 'bytes' }, // Auto-added
],
},
] as const;

Encryption Process​

  1. Detects encrypted types from ABI
  2. Creates encrypted input
  3. Encrypts specified values
  4. Builds final arguments including handles and proof
  5. Sends transaction

Best Practices​

1. Use writeAsync for Error Handling​

try {
const receipt = await writeAsync({ ... });
// Handle success
} catch (error) {
// Handle error
}

2. Handle Loading States​

<button onClick={handleWrite} disabled={isLoading}>
{isLoading ? 'Processing...' : 'Submit'}
</button>

3. Reset After Success​

useEffect(() => {
if (isSuccess) {
reset(); // Reset for next operation
}
}, [isSuccess, reset]);

4. Validate Before Writing​

const handleWrite = () => {
if (!isValidInput()) {
alert('Invalid input');
return;
}

write({ functionName: 'submit', args: [...] });
};

Notes​

Provider Required

This hook requires FhevmProvider and a connected wallet with signer.

Automatic Encryption

The hook automatically encrypts arguments based on ABI types. No manual encryption needed!

Gas Estimation

Gas is automatically estimated by ethers. You can override with the gasLimit parameter.

Transaction Confirmation

The hook waits for transaction confirmation before updating state. Use data.transactionHash to track pending transactions.