Write Contract
Use writeContract() to send a state-changing transaction to a deployed smart contract. Unlike readContract, this method submits an on-chain transaction, costs gas, and returns a transaction hash that you can poll for confirmation.
Method Signature
client.writeContract(params: ContractWriteParams): Promise<ApiResponse<ContractWriteResult>>
ContractWriteParams
import type { ContractWriteParams } from '@one_deploy/sdk';
interface ContractWriteParams {
contractAddress: string; // Target contract address
chainId: number; // Chain to transact on
functionName: string; // Solidity function name
args?: unknown[]; // Positional arguments
abi?: Record<string, unknown>[]; // ABI array (optional if contract is indexed)
value?: string; // Native token value in wei (e.g. ETH, MATIC)
gasLimit?: string; // Optional gas limit override
}
ContractWriteResult
interface ContractWriteResult {
transactionHash: string; // The submitted tx hash
chainId: number;
status: 'pending' | 'submitted';
}
After receiving the transaction hash, use getTransactionStatus() to track confirmation.
Examples
ERC-20: approve
Grant a spender an allowance to transfer tokens on your behalf:
import { useOneEngine } from '@one_deploy/sdk';
function ApproveButton({
token,
spender,
amount,
}: {
token: string;
spender: string;
amount: string;
}) {
const { client } = useOneEngine();
async function handleApprove() {
const res = await client.writeContract({
contractAddress: token,
chainId: 137,
functionName: 'approve',
args: [spender, amount], // amount in smallest unit (wei / raw)
});
if (!res.success) {
console.error('Approve failed:', res.error?.message);
return;
}
console.log('Tx submitted:', res.data.transactionHash);
// Now poll for confirmation
await waitForConfirmation(client, res.data.transactionHash, 137);
}
return <button onClick={handleApprove}>Approve</button>;
}
ERC-20: transfer
Transfer tokens to another address:
const res = await client.writeContract({
contractAddress: '0xA0b8...3E7a', // USDC on Ethereum
chainId: 1,
functionName: 'transfer',
args: [
'0xRecipient...Address', // to
'1000000', // amount (1 USDC = 1e6 for 6-decimal tokens)
],
});
if (res.success) {
console.log('Transfer submitted:', res.data.transactionHash);
}
ERC-721: safeTransferFrom
Transfer an NFT safely (receiver must implement onERC721Received):
const res = await client.writeContract({
contractAddress: '0xBC4C...a1F9',
chainId: 1,
functionName: 'safeTransferFrom',
args: [
'0xFromAddress...', // from
'0xToAddress...', // to
42, // tokenId
],
});
if (res.success) {
console.log('NFT transfer submitted:', res.data.transactionHash);
}
Custom Contract with ETH Value
Call a payable function and attach native ETH:
const customAbi = [
{
inputs: [{ name: 'referrer', type: 'address' }],
name: 'mintWithReferral',
outputs: [],
stateMutability: 'payable',
type: 'function',
},
];
const res = await client.writeContract({
contractAddress: '0x5566...7788',
chainId: 1,
functionName: 'mintWithReferral',
args: ['0xReferrerAddress...'],
abi: customAbi,
value: '50000000000000000', // 0.05 ETH in wei
});
if (res.success) {
console.log('Mint tx:', res.data.transactionHash);
}
Use the built-in parseEther utility or any BigNumber library to convert human-readable values to wei. The value field always expects a string denominated in the chain's smallest unit.
Transaction Confirmation Flow
After writeContract returns a transaction hash, poll getTransactionStatus to wait for on-chain confirmation:
async function waitForConfirmation(
client: InstanceType<typeof import('@one_deploy/sdk').OneEngineClient>,
txHash: string,
chainId: number,
maxAttempts = 30,
intervalMs = 2000,
): Promise<void> {
for (let i = 0; i < maxAttempts; i++) {
const status = await client.getTransactionStatus(txHash, chainId);
if (status.data.status === 'confirmed') {
console.log('Transaction confirmed in block', status.data.blockNumber);
return;
}
if (status.data.status === 'failed') {
throw new Error(`Transaction failed: ${status.data.reason}`);
}
// status.data.status === 'pending' -- keep polling
await new Promise((r) => setTimeout(r, intervalMs));
}
throw new Error('Transaction confirmation timed out');
}
getTransactionStatus Response
interface TransactionStatus {
transactionHash: string;
chainId: number;
status: 'pending' | 'confirmed' | 'failed';
blockNumber?: number;
gasUsed?: string;
reason?: string; // Present when status is 'failed'
}
Full React Example
Combining write + confirmation in a single component:
import { useOneEngine } from '@one_deploy/sdk';
import { useState } from 'react';
function TransferToken() {
const { client } = useOneEngine();
const [status, setStatus] = useState<string>('idle');
async function handleTransfer() {
setStatus('submitting');
const res = await client.writeContract({
contractAddress: '0xA0b8...3E7a',
chainId: 137,
functionName: 'transfer',
args: ['0xRecipient...', '5000000'], // 5 USDC
});
if (!res.success) {
setStatus(`error: ${res.error?.message}`);
return;
}
setStatus('pending');
const txHash = res.data.transactionHash;
// Poll for confirmation
const interval = setInterval(async () => {
const txRes = await client.getTransactionStatus(txHash, 137);
if (txRes.data.status === 'confirmed') {
clearInterval(interval);
setStatus('confirmed');
} else if (txRes.data.status === 'failed') {
clearInterval(interval);
setStatus(`failed: ${txRes.data.reason}`);
}
}, 2000);
}
return (
<div>
<button onClick={handleTransfer} disabled={status === 'submitting' || status === 'pending'}>
Transfer 5 USDC
</button>
<p>Status: {status}</p>
</div>
);
}
Error Handling
const res = await client.writeContract({
contractAddress: '0xToken...',
chainId: 1,
functionName: 'transfer',
args: ['0xTo...', '1000000000000000000'],
});
if (!res.success) {
switch (res.error?.code) {
case 'INSUFFICIENT_FUNDS':
console.error('Not enough balance to cover the transfer + gas.');
break;
case 'EXECUTION_REVERTED':
console.error('Contract reverted:', res.error.message);
break;
case 'GAS_ESTIMATION_FAILED':
console.error('Could not estimate gas. The transaction would likely revert.');
break;
case 'INVALID_ARGS':
console.error('Arguments do not match the function signature.');
break;
default:
console.error('Unexpected error:', res.error?.message);
}
}
Next Steps
- Read Contract -- query on-chain state without sending a transaction.
- Deploy Contract -- deploy new contracts from templates or custom bytecode.
- Contract Events & Webhooks -- subscribe to events emitted by your contracts.