Aller au contenu principal

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.