读取合约
使用 readContract() 调用任意已部署智能合约上的只读(view / pure)函数。此方法不会发送交易或消耗 Gas -- 它查询链上状态并返回结果。
方法签名
client.readContract(params: ContractReadParams): Promise<ApiResponse<unknown>>
ContractReadParams
import type { ContractReadParams } from '@one_deploy/sdk';
interface ContractReadParams {
contractAddress: string; // 已部署的合约地址
chainId: number; // 要读取的链
functionName: string; // Solidity 函数名
args?: unknown[]; // 函数的位置参数
abi?: Record<string, unknown>[]; // ABI 数组(如果合约已被索引则可选)
}
当合约已被 Engine 索引(例如你通过 SDK 部署的合约或知名代币),abi 字段是可选的。对于未索引的合约,至少需要提供你要调用的函数的 ABI 片段。
ApiResponse 封装
每个 Engine 方法都返回标准化的 ApiResponse<T> 信封:
interface ApiResponse<T> {
data: T;
success: boolean;
error?: {
code: string;
message: string;
};
meta?: Record<string, unknown>;
}
对于 readContract,T 从 Solidity 函数的返回类型推断。由于 Engine 无法在编译时知道类型,SDK 将其类型化为 unknown -- 你应该在应用代码中进行类型转换或缩窄。
示例
ERC-20: balanceOf
import { useOneEngine } from '@one_deploy/sdk';
function TokenBalance({ token, wallet }: { token: string; wallet: string }) {
const { client } = useOneEngine();
async function fetchBalance() {
const res = await client.readContract({
contractAddress: token,
chainId: 137, // Polygon
functionName: 'balanceOf',
args: [wallet],
});
// balanceOf 返回 uint256 -- Engine 将其序列化为字符串
const rawBalance = res.data as string;
console.log('Raw balance:', rawBalance);
}
return <button onClick={fetchBalance}>Check Balance</button>;
}
ERC-20: name、symbol、decimals
使用 Promise.all 并行读取多个属性:
const [nameRes, symbolRes, decimalsRes] = await Promise.all([
client.readContract({
contractAddress: '0xA0b8...3E7a',
chainId: 1,
functionName: 'name',
}),
client.readContract({
contractAddress: '0xA0b8...3E7a',
chainId: 1,
functionName: 'symbol',
}),
client.readContract({
contractAddress: '0xA0b8...3E7a',
chainId: 1,
functionName: 'decimals',
}),
]);
const name = nameRes.data as string; // "USD Coin"
const symbol = symbolRes.data as string; // "USDC"
const decimals = decimalsRes.data as number; // 6
ERC-721: ownerOf
const res = await client.readContract({
contractAddress: '0xBC4C...a1F9',
chainId: 1,
functionName: 'ownerOf',
args: [42], // tokenId
});
const owner = res.data as string;
console.log('Token #42 owner:', owner);
ERC-721: tokenURI
const res = await client.readContract({
contractAddress: '0xBC4C...a1F9',
chainId: 1,
functionName: 'tokenURI',
args: [42],
});
const uri = res.data as string;
// "ipfs://Qm.../42.json"
带 ABI 片段的自定义合约
当调用 Engine 未索引的合约上的函数时,直接提供 ABI 片段:
const customAbi = [
{
inputs: [{ name: 'account', type: 'address' }],
name: 'getStakeInfo',
outputs: [
{ name: 'stakedAmount', type: 'uint256' },
{ name: 'rewardDebt', type: 'uint256' },
],
stateMutability: 'view',
type: 'function',
},
];
const res = await client.readContract({
contractAddress: '0x9988...ccDD',
chainId: 42161, // Arbitrum
functionName: 'getStakeInfo',
args: ['0xYourWallet...'],
abi: customAbi,
});
// 元组返回值序列化为数组
const [stakedAmount, rewardDebt] = res.data as [string, string];
console.log('Staked:', stakedAmount, 'Reward debt:', rewardDebt);
错误处理
const res = await client.readContract({
contractAddress: '0xDEAD...0000',
chainId: 1,
functionName: 'balanceOf',
args: ['0xUser...'],
});
if (!res.success) {
console.error(`Read failed [${res.error?.code}]: ${res.error?.message}`);
// 可能的错误代码:
// CONTRACT_NOT_FOUND -- 该地址在此链上不是合约
// FUNCTION_NOT_FOUND -- 函数名与 ABI 不匹配
// EXECUTION_REVERTED -- 调用在链上回滚
// INVALID_ARGS -- 参数数量或类型错误
return;
}
console.log('Result:', res.data);
在 React 外使用
在 Node.js 或 Edge 运行时中,直接实例化客户端:
import { OneEngineClient } from '@one_deploy/sdk';
const client = new OneEngineClient({
apiKey: process.env.ONE_API_KEY!,
projectId: process.env.ONE_PROJECT_ID!,
});
const res = await client.readContract({
contractAddress: '0xA0b8...3E7a',
chainId: 1,
functionName: 'totalSupply',
});
console.log('Total supply:', res.data);