⚠️Blast API (blastapi.io) ends Oct 31. Migrate to Dwellir and skip Alchemy's expensive compute units.
Switch Today →
Skip to main content

eth_call

Executes a new message call immediately without creating a transaction on the blockchain.

When to Use This Method

Use eth_call to:

  • Read Contract State - Query view/pure functions without gas costs
  • Simulate Transactions - Test transaction execution without broadcasting
  • Validate Parameters - Check if a transaction will succeed
  • Get Return Values - Retrieve data from smart contracts

Parameters

  1. Transaction Object - The transaction call object

    • from (optional): Address the transaction is sent from
    • to: Address the transaction is directed to (contract address)
    • gas (optional): Gas provided for the transaction
    • gasPrice (optional): Gas price in wei
    • value (optional): Value sent with this transaction
    • data: Hash of the method signature and encoded parameters
  2. Block Parameter - Block number, or string "latest", "earliest" or "pending"

{
"jsonrpc": "2.0",
"method": "eth_call",
"params": [
{
"to": "0x...",
"data": "0x..."
},
"latest"
],
"id": 1
}

Returns

DATA - The return value of the executed contract method.

Implementation Examples

# Read ERC-20 token balance
curl -X POST https://api-tron-jsonrpc.dwellir.com/YOUR_API_KEY \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "eth_call",
"params": [
{
"to": "0xa614f803b6fd780986a42c78ec9c7f77e6ded13c",
"data": "0x70a08231000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045"
},
"latest"
],
"id": 1
}'

Example Response

{
"jsonrpc": "2.0",
"id": 1,
"result": "0x00000000000000000000000000000000000000000000000000000000000004d2"
}

Common Use Cases

1. Read ERC-20 Token Information

async function getTokenInfo(tokenAddress) {
const abi = [
'function name() view returns (string)',
'function symbol() view returns (string)',
'function decimals() view returns (uint8)',
'function totalSupply() view returns (uint256)'
];

const contract = new ethers.Contract(tokenAddress, abi, provider);

const [name, symbol, decimals, totalSupply] = await Promise.all([
contract.name(),
contract.symbol(),
contract.decimals(),
contract.totalSupply()
]);

return {
name,
symbol,
decimals,
totalSupply: ethers.formatUnits(totalSupply, decimals)
};
}

2. Check Allowance Before Transfer

async function checkAndApprove(tokenAddress, spender, amount) {
const abi = [
'function allowance(address owner, address spender) view returns (uint256)',
'function approve(address spender, uint256 amount) returns (bool)'
];

const contract = new ethers.Contract(tokenAddress, abi, provider);
const currentAllowance = await contract.allowance(userAddress, spender);

if (currentAllowance < amount) {
console.log('Insufficient allowance, approval needed');
// Create approval transaction
return false;
}

return true;
}

3. Simulate Transaction Before Sending

async function simulateTransaction(to, data, value = '0x0') {
try {
const result = await provider.call({
to,
data,
value,
from: userAddress // Important for access control
});

console.log('Simulation successful:', result);
return { success: true, result };
} catch (error) {
console.error('Transaction will fail:', error.message);
return { success: false, error: error.message };
}
}

Best Practices

  1. Always specify from for access-controlled functions
  2. Use latest block for current state
  3. Handle reverts gracefully
  4. Cache read results when appropriate
  5. Validate addresses before calling

Error Codes

CodeMessageDescription
-32600Invalid RequestMalformed request
-32602Invalid paramsInvalid method parameters
-32603Internal errorInternal JSON-RPC error
-32000Execution revertedContract execution failed
3Execution errorEVM execution error