⚠️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

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

  1. Transaction Object (required)

    • from (optional): 20-byte address the call is sent from
    • to (required): 20-byte address the call is directed to
    • gas (optional): Integer gas limit for the call
    • gasPrice (optional): Integer gas price in wei
    • value (optional): Integer value in wei sent with the call
    • data (optional): Hash of method signature and encoded parameters
  2. Block Parameter (optional, default: "latest")

    • Block number as hex string (e.g., "0x10")
    • Block tags: "latest", "earliest", "pending"
{
"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

# 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
}'

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 CodeDescriptionSolution
3Execution revertedCheck contract logic and parameters
-32000Insufficient gasIncrease gas limit in call
-32016Invalid blockUse valid block number or tag
-32602Invalid paramsVerify 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
}