eth_call
Executes a new message call immediately without creating a transaction on the blockchain.
When to Use This Method
eth_call
is essential for:
- Contract State Reading - Query contract variables and view functions
- Transaction Simulation - Preview transaction results before sending
- Gas Estimation Helper - Test calls before estimating gas
- Static Analysis - Analyze contract behavior without state changes
- View Function Calls - Execute read-only contract methods
Parameters
-
Transaction Object (required)
from
(optional): 20-byte address the call is sent fromto
(required): 20-byte address the call is directed togas
(optional): Integer gas limit for the callgasPrice
(optional): Integer gas price in weivalue
(optional): Integer value in wei sent with the calldata
(optional): Hash of method signature and encoded parameters
-
Block Parameter (optional, default:
"latest"
)- Block number as hex string (e.g.,
"0x10"
) - Block tags:
"latest"
,"earliest"
,"pending"
- Block number as hex string (e.g.,
{
"jsonrpc": "2.0",
"method": "eth_call",
"params": [
{
"to": "0xContractAddress",
"data": "0x70a08231000000000000000000000000UserAddress"
},
"latest"
],
"id": 1
}
Returns
DATA
- The return value of the executed contract method.
- Type: Hexadecimal string
- Format:
0x
prefixed - Content: ABI-encoded return data from the contract call
Implementation Examples
- cURL
- JavaScript
- Python
- Go
# Query ERC-20 token balance
curl -X POST https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "eth_call",
"params": [
{
"to": "0xa0b86a33e6e22b3b7c9c7ff5b0b8bc55c4bdb9b1",
"data": "0x70a08231000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c1"
},
"latest"
],
"id": 1
}'
# Call contract view function with no parameters
curl -X POST https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "eth_call",
"params": [
{
"to": "0xContractAddress",
"data": "0x18160ddd"
},
"latest"
],
"id": 1
}'
// Using fetch API for ERC-20 balanceOf call
const getTokenBalance = async (tokenAddress, userAddress) => {
// Encode balanceOf(address) function call
const methodId = '0x70a08231'; // balanceOf function selector
const paddedAddress = userAddress.slice(2).padStart(64, '0');
const data = methodId + paddedAddress;
const response = await fetch('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
method: 'eth_call',
params: [
{
to: tokenAddress,
data: data
},
'latest'
],
id: 1
})
});
const result = await response.json();
const balance = BigInt(result.result);
console.log('Token balance:', balance.toString());
return balance;
};
// Using ethers.js for contract calls
import { JsonRpcProvider, Contract } from 'ethers';
const provider = new JsonRpcProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY');
// Method 1: Using contract instance
const erc20Abi = ['function balanceOf(address) view returns (uint256)'];
const contract = new Contract(tokenAddress, erc20Abi, provider);
const balance = await contract.balanceOf(userAddress);
// Method 2: Raw call with provider
const callResult = await provider.call({
to: tokenAddress,
data: '0x70a08231' + userAddress.slice(2).padStart(64, '0')
});
// Simulate transaction before sending
async function simulateTransaction(txParams) {
try {
const result = await provider.call(txParams);
console.log('Call would succeed, result:', result);
return { success: true, result };
} catch (error) {
console.log('Call would fail:', error.message);
return { success: false, error: error.message };
}
}
import requests
import json
from web3 import Web3
def call_contract_method(contract_address, data, block='latest'):
url = 'https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY'
payload = {
"jsonrpc": "2.0",
"method": "eth_call",
"params": [
{
"to": contract_address,
"data": data
},
block
],
"id": 1
}
response = requests.post(url, json=payload)
data = response.json()
return data.get('result')
# Get ERC-20 token balance
def get_token_balance(token_address, user_address):
# balanceOf(address) function selector + padded address
method_id = '0x70a08231'
padded_address = user_address[2:].zfill(64)
data = method_id + padded_address
result = call_contract_method(token_address, data)
balance = int(result, 16) if result else 0
print(f"Token balance: {balance}")
return balance
# Using web3.py
w3 = Web3(Web3.HTTPProvider('https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY'))
# Create contract instance
contract_abi = [{"inputs":[{"name":"account","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]
contract = w3.eth.contract(address=token_address, abi=contract_abi)
# Call contract method
balance = contract.functions.balanceOf(user_address).call()
print(f"Balance: {balance}")
# Raw call
result = w3.eth.call({
'to': token_address,
'data': '0x70a08231' + user_address[2:].zfill(64)
})
balance = int.from_bytes(result, byteorder='big')
package main
import (
"context"
"fmt"
"log"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum"
)
func main() {
client, err := ethclient.Dial("https://api-berachain-mainnet.n.dwellir.com/YOUR_API_KEY")
if err != nil {
log.Fatal(err)
}
// Contract call example - ERC20 balanceOf
tokenAddress := common.HexToAddress("0xYourTokenAddress")
userAddress := common.HexToAddress("0xUserAddress")
// Encode function call: balanceOf(address)
methodID := common.FromHex("0x70a08231")
paddedAddress := common.LeftPadBytes(userAddress.Bytes(), 32)
data := append(methodID, paddedAddress...)
// Create call message
msg := ethereum.CallMsg{
To: &tokenAddress,
Data: data,
}
// Execute call
result, err := client.CallContract(context.Background(), msg, nil)
if err != nil {
log.Fatal(err)
}
// Decode result as big integer
balance := new(big.Int).SetBytes(result)
fmt.Printf("Token balance: %s\n", balance.String())
// Simulate transaction
simulateResult, err := client.CallContract(context.Background(), ethereum.CallMsg{
From: userAddress,
To: &tokenAddress,
Value: big.NewInt(0),
Data: data,
}, nil)
if err != nil {
fmt.Printf("Simulation failed: %v\n", err)
} else {
fmt.Printf("Simulation successful: %x\n", simulateResult)
}
}
Response Example
Successful Response (ERC-20 Balance)
{
"jsonrpc": "2.0",
"id": 1,
"result": "0x0000000000000000000000000000000000000000000000001bc16d674ec80000"
}
Successful Response (String Return)
{
"jsonrpc": "2.0",
"id": 1,
"result": "0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000084265726120546f6b656e000000000000000000000000000000000000000000"
}
Error Response (Revert)
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": 3,
"message": "execution reverted",
"data": "0x08c379a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001a4e6f7420656e6f7567682062616c616e636520746f207472616e73666572000000"
}
}
Common Use Cases
1. ERC-20 Token Operations
Query token information and balances:
class TokenHelper {
constructor(provider, tokenAddress) {
this.provider = provider;
this.tokenAddress = tokenAddress;
}
async getName() {
const data = '0x06fdde03'; // name() selector
const result = await this.provider.call({
to: this.tokenAddress,
data: data
});
return this.decodeString(result);
}
async getSymbol() {
const data = '0x95d89b41'; // symbol() selector
return this.decodeString(await this.provider.call({
to: this.tokenAddress,
data: data
}));
}
async getDecimals() {
const data = '0x313ce567'; // decimals() selector
const result = await this.provider.call({
to: this.tokenAddress,
data: data
});
return parseInt(result, 16);
}
async balanceOf(address) {
const data = '0x70a08231' + address.slice(2).padStart(64, '0');
const result = await this.provider.call({
to: this.tokenAddress,
data: data
});
return BigInt(result);
}
decodeString(hex) {
// Simple string decoding (assumes standard ABI encoding)
const data = hex.slice(2);
const length = parseInt(data.slice(64, 128), 16);
const stringData = data.slice(128, 128 + length * 2);
return Buffer.from(stringData, 'hex').toString();
}
}
2. Transaction Simulation
Preview transaction outcomes:
async function simulateTransfer(tokenContract, from, to, amount) {
const transferData = tokenContract.interface.encodeFunctionData('transfer', [to, amount]);
try {
const result = await provider.call({
from: from,
to: tokenContract.address,
data: transferData
});
// Successful simulation
console.log('Transfer simulation successful');
return { success: true, result };
} catch (error) {
// Failed simulation - check reason
if (error.data) {
try {
const reason = tokenContract.interface.parseError(error.data);
console.log('Transfer would fail:', reason);
} catch {
console.log('Transfer would fail with unknown error');
}
}
return { success: false, error: error.message };
}
}
3. Multi-Call Pattern
Batch multiple calls efficiently:
class MultiCall {
constructor(provider, multicallAddress) {
this.provider = provider;
this.multicallAddress = multicallAddress;
}
async aggregate(calls) {
// Encode multicall aggregate function
const targets = calls.map(call => call.target);
const callDatas = calls.map(call => call.data);
// This would use a multicall contract
const encoded = this.encodeMulticall(targets, callDatas);
const result = await this.provider.call({
to: this.multicallAddress,
data: encoded
});
return this.decodeMulticallResult(result);
}
async batchTokenData(tokenAddress, userAddresses) {
const calls = userAddresses.map(address => ({
target: tokenAddress,
data: '0x70a08231' + address.slice(2).padStart(64, '0') // balanceOf
}));
return await this.aggregate(calls);
}
}
Performance Optimization
Call Result Caching
Cache frequently accessed contract data:
class ContractCallCache {
constructor(ttl = 10000) { // 10 second default TTL
this.cache = new Map();
this.ttl = ttl;
}
getCacheKey(to, data, block) {
return `${to}-${data}-${block}`;
}
async call(provider, to, data, block = 'latest') {
const key = this.getCacheKey(to, data, block);
const cached = this.cache.get(key);
if (cached && Date.now() - cached.timestamp < this.ttl) {
return cached.result;
}
const result = await provider.call({ to, data }, block);
this.cache.set(key, {
result,
timestamp: Date.now()
});
return result;
}
invalidate(to, data, block) {
const key = this.getCacheKey(to, data, block);
this.cache.delete(key);
}
clear() {
this.cache.clear();
}
}
Batch Processing
Process multiple calls in parallel:
async function batchContractCalls(provider, calls) {
const promises = calls.map(async (call, index) => {
try {
const result = await provider.call(call.params);
return { index, success: true, result };
} catch (error) {
return { index, success: false, error: error.message };
}
});
const results = await Promise.all(promises);
return results.sort((a, b) => a.index - b.index);
}
// Usage
const calls = [
{ params: { to: tokenAddress, data: '0x06fdde03' } }, // name()
{ params: { to: tokenAddress, data: '0x95d89b41' } }, // symbol()
{ params: { to: tokenAddress, data: '0x313ce567' } } // decimals()
];
const results = await batchContractCalls(provider, calls);
Error Handling
Common errors and solutions:
Error Code | Description | Solution |
---|---|---|
3 | Execution reverted | Check contract logic and parameters |
-32000 | Insufficient gas | Increase gas limit in call |
-32016 | Invalid block | Use valid block number or tag |
-32602 | Invalid params | Verify to address and data format |
async function safeContractCall(provider, callParams, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
return await provider.call(callParams);
} catch (error) {
console.error(`Call attempt ${i + 1} failed:`, error.message);
if (error.code === 3) {
// Contract reverted - don't retry
throw new Error(`Contract call reverted: ${error.message}`);
}
if (error.code === -32602) {
// Invalid params - don't retry
throw new Error(`Invalid call parameters: ${error.message}`);
}
if (i === maxRetries - 1) {
throw error;
}
// Exponential backoff for retryable errors
await new Promise(r => setTimeout(r, Math.pow(2, i) * 1000));
}
}
}
// Usage with error handling
try {
const result = await safeContractCall(provider, {
to: contractAddress,
data: encodedFunctionCall
});
// Process successful result
console.log('Call result:', result);
} catch (error) {
console.error('Contract call failed:', error.message);
// Handle error appropriately
}