eth_call
Executes a new message call immediately without creating a transaction on the blockchain. Used for reading smart contract data and simulating transactions.
Save 80% on
eth_call
RequestsAlchemy = $11.70 per million eth_call
requests
Quicknode = $12.40 per million eth_call
requests
Dwellir = $2 per million eth_call
requests
Quicknode is 6X more expensive for eth_call
s!
When to Use This Method
Use eth_call
to:
- Read Contract State - Query data from smart contracts
- Simulate Transactions - Test transaction outcomes without gas costs
- View Functions - Call contract view/pure functions
- Cross-Chain Queries - Read omnichain contract state
- Gas Estimation - Pre-calculate complex operations
Parameters
-
Transaction Object (required):
from
(optional): 20 bytes - Address the transaction is sent fromto
(required): 20 bytes - Address the transaction is directed togas
(optional): Hexadecimal value of gas providedgasPrice
(optional): Hexadecimal value of gas pricevalue
(optional): Hexadecimal value sent with transactiondata
(optional): Hash of method signature and encoded parameters
-
Block Parameter (optional):
latest
- Latest block (default)earliest
- Genesis blockpending
- Pending state- Block number as hexadecimal
{
"jsonrpc": "2.0",
"method": "eth_call",
"params": [
{
"to": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb8",
"data": "0x70a08231000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045"
},
"latest"
],
"id": 1
}
Returns
DATA
- The return value of the executed contract function.
- Type: Hexadecimal string
- Format:
0x
prefixed - Decoding: Required based on contract ABI
Implementation Examples
- cURL
- JavaScript
- Python
# Query ERC20 balance
curl -X POST https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "eth_call",
"params": [
{
"to": "0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf",
"data": "0x70a08231000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045"
},
"latest"
],
"id": 1
}'
# Query omnichain contract state
curl -X POST https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "eth_call",
"params": [
{
"to": "0x239e96c8f17C85c30100AC26F635Ea15f23E9c67",
"data": "0x2e64cec1"
},
"latest"
],
"id": 1
}'
// Using fetch API
async function readContract(contractAddress, data) {
const response = await fetch('https://api-xdc-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: contractAddress,
data: data
},
'latest'
],
id: 1,
}),
});
const result = await response.json();
return result.result;
}
// Using ethers.js with ABI
import { ethers } from 'ethers';
const provider = new ethers.JsonRpcProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');
// ERC20 token contract
const tokenABI = [
'function balanceOf(address account) view returns (uint256)',
'function totalSupply() view returns (uint256)',
'function symbol() view returns (string)',
'function decimals() view returns (uint8)'
];
const tokenContract = new ethers.Contract(
'0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf', // ZETA token
tokenABI,
provider
);
// Read token balance
const balance = await tokenContract.balanceOf('0xd8da6bf26964af9d7eed9e03e53415d37aa96045');
console.log('ZETA Balance:', ethers.formatEther(balance));
// Omnichain contract example
const omnichainABI = [
'function getConnectedChains() view returns (uint256[])',
'function getCrossChainBalance(address account, uint256 chainId) view returns (uint256)',
'function isPendingCrossChain(bytes32 messageId) view returns (bool)'
];
const omnichainContract = new ethers.Contract(
'0x239e96c8f17C85c30100AC26F635Ea15f23E9c67',
omnichainABI,
provider
);
// Query cross-chain state
const connectedChains = await omnichainContract.getConnectedChains();
console.log('Connected chains:', connectedChains);
// Using web3.js
import Web3 from 'web3';
const web3 = new Web3('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY');
// Manual encoding
const data = web3.eth.abi.encodeFunctionCall({
name: 'balanceOf',
type: 'function',
inputs: [{
type: 'address',
name: 'account'
}]
}, ['0xd8da6bf26964af9d7eed9e03e53415d37aa96045']);
const result = await web3.eth.call({
to: '0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf',
data: data
});
const balance = web3.utils.toBigInt(result);
console.log('Balance:', balance);
import json
import requests
from web3 import Web3
from eth_abi import encode, decode
# Using requests
def call_contract(contract_address, data):
url = 'https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY'
payload = {
'jsonrpc': '2.0',
'method': 'eth_call',
'params': [
{
'to': contract_address,
'data': data
},
'latest'
],
'id': 1
}
response = requests.post(url, json=payload)
return response.json()['result']
# Using web3.py
w3 = Web3(Web3.HTTPProvider('https://api-xdc-mainnet.n.dwellir.com/YOUR_API_KEY'))
# ERC20 token balance query
token_address = '0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf'
account = '0xd8da6bf26964af9d7eed9e03e53415d37aa96045'
# Encode function call
function_selector = w3.keccak(text='balanceOf(address)')[:4]
encoded_address = encode(['address'], [account])
data = function_selector + encoded_address
# Make the call
result = w3.eth.call({
'to': token_address,
'data': data
})
# Decode result
balance = int(result.hex(), 16)
print(f'ZETA Balance: {w3.from_wei(balance, "ether")}')
# Using contract ABI
contract_abi = [
{
"inputs": [{"name": "account", "type": "address"}],
"name": "balanceOf",
"outputs": [{"name": "", "type": "uint256"}],
"type": "function",
"stateMutability": "view"
}
]
contract = w3.eth.contract(address=token_address, abi=contract_abi)
balance = contract.functions.balanceOf(account).call()
print(f'Token balance: {balance}')
Example Response
{
"jsonrpc": "2.0",
"id": 1,
"result": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
}
Decoding: 0x56bc75e2d63100000
= 100,000,000,000,000,000,000 (100 ZETA with 18 decimals)
Omnichain Contract Calls
xdc enables unique cross-chain contract interactions:
Reading Cross-Chain State
// Query balances across multiple chains from one contract
const omnichainVault = new ethers.Contract(vaultAddress, vaultABI, provider);
async function getMultiChainBalances(userAddress) {
const chains = [1, 56, 137, 42161]; // ETH, BSC, Polygon, Arbitrum
const balances = {};
for (const chainId of chains) {
const balance = await omnichainVault.getBalance(userAddress, chainId);
balances[chainId] = ethers.formatEther(balance);
}
return balances;
}
Cross-Chain Oracle Queries
// Read price feeds from multiple chains
const priceOracle = new ethers.Contract(oracleAddress, oracleABI, provider);
async function getCrossChainPrices(token) {
const prices = await priceOracle.getPricesAcrossChains(token);
return {
ethereum: prices[0] / 1e8,
bsc: prices[1] / 1e8,
polygon: prices[2] / 1e8,
average: prices[3] / 1e8
};
}
Common Use Cases
1. Token Balance Queries
class TokenBalanceReader {
constructor(provider) {
this.provider = provider;
this.cache = new Map();
}
async getBalance(tokenAddress, accountAddress) {
const cacheKey = `${tokenAddress}-${accountAddress}`;
// Check cache (valid for 10 seconds)
if (this.cache.has(cacheKey)) {
const cached = this.cache.get(cacheKey);
if (Date.now() - cached.timestamp < 10000) {
return cached.balance;
}
}
// ERC20 balanceOf selector: 0x70a08231
const data = '0x70a08231' +
accountAddress.slice(2).padStart(64, '0');
const result = await this.provider.call({
to: tokenAddress,
data: data
});
const balance = ethers.formatEther(result);
// Cache result
this.cache.set(cacheKey, {
balance,
timestamp: Date.now()
});
return balance;
}
async getMultipleBalances(tokens, account) {
const balances = {};
// Batch calls for efficiency
const promises = tokens.map(token =>
this.getBalance(token.address, account)
);
const results = await Promise.all(promises);
tokens.forEach((token, index) => {
balances[token.symbol] = results[index];
});
return balances;
}
}
2. DEX Price Queries
async function getDEXPrices(pairAddress) {
const pairABI = [
'function getReserves() view returns (uint112 reserve0, uint112 reserve1, uint32 timestamp)',
'function token0() view returns (address)',
'function token1() view returns (address)'
];
const pair = new ethers.Contract(pairAddress, pairABI, provider);
// Get reserves and tokens
const [reserves, token0, token1] = await Promise.all([
pair.getReserves(),
pair.token0(),
pair.token1()
]);
// Calculate price
const price0To1 = Number(reserves.reserve1) / Number(reserves.reserve0);
const price1To0 = Number(reserves.reserve0) / Number(reserves.reserve1);
return {
token0Address: token0,
token1Address: token1,
price0To1,
price1To0,
liquidity: {
token0: ethers.formatEther(reserves.reserve0),
token1: ethers.formatEther(reserves.reserve1)
}
};
}
3. NFT Metadata Reading
async function getNFTMetadata(nftAddress, tokenId) {
const nftABI = [
'function tokenURI(uint256 tokenId) view returns (string)',
'function ownerOf(uint256 tokenId) view returns (address)',
'function balanceOf(address owner) view returns (uint256)'
];
const nft = new ethers.Contract(nftAddress, nftABI, provider);
try {
const [tokenURI, owner] = await Promise.all([
nft.tokenURI(tokenId),
nft.ownerOf(tokenId)
]);
// Fetch metadata from URI
const metadata = await fetch(tokenURI).then(r => r.json());
return {
tokenId,
owner,
tokenURI,
metadata
};
} catch (error) {
console.error('Error reading NFT:', error);
throw error;
}
}
4. Governance Voting Power
async function getVotingPower(governanceAddress, voterAddress, proposalId) {
const govABI = [
'function getVotes(address account) view returns (uint256)',
'function proposals(uint256) view returns (tuple(uint256 id, address proposer, uint256 forVotes, uint256 againstVotes, uint256 startBlock, uint256 endBlock, bool executed))',
'function hasVoted(uint256 proposalId, address account) view returns (bool)'
];
const governance = new ethers.Contract(governanceAddress, govABI, provider);
const [votes, proposal, hasVoted] = await Promise.all([
governance.getVotes(voterAddress),
governance.proposals(proposalId),
governance.hasVoted(proposalId, voterAddress)
]);
return {
votingPower: ethers.formatEther(votes),
proposal: {
forVotes: ethers.formatEther(proposal.forVotes),
againstVotes: ethers.formatEther(proposal.againstVotes),
active: proposal.endBlock > await provider.getBlockNumber()
},
hasVoted
};
}
5. Cross-Chain Bridge Status
async function checkBridgeTransfer(bridgeAddress, transferId) {
const bridgeABI = [
'function getTransferStatus(bytes32 transferId) view returns (uint8 status)',
'function getTransferDetails(bytes32 transferId) view returns (tuple(address sender, address recipient, uint256 amount, uint256 sourceChain, uint256 destChain, uint256 timestamp))'
];
const bridge = new ethers.Contract(bridgeAddress, bridgeABI, provider);
const [status, details] = await Promise.all([
bridge.getTransferStatus(transferId),
bridge.getTransferDetails(transferId)
]);
const statusMap = {
0: 'Pending',
1: 'InProgress',
2: 'Completed',
3: 'Failed'
};
return {
status: statusMap[status],
amount: ethers.formatEther(details.amount),
sourceChain: details.sourceChain,
destChain: details.destChain,
timestamp: new Date(Number(details.timestamp) * 1000)
};
}
Gas Optimization
Batch Reading
// Efficient multi-call pattern
async function batchRead(calls) {
const multicallAddress = '0xcA11bde05977b3631167028862bE2a173976CA11';
const multicallABI = ['function aggregate(tuple(address target, bytes callData)[] calls) view returns (uint256 blockNumber, bytes[] returnData)'];
const multicall = new ethers.Contract(multicallAddress, multicallABI, provider);
const [, results] = await multicall.aggregate(calls);
return results;
}
Error Handling
Common Error Patterns
async function safeContractCall(contract, method, params) {
try {
const result = await contract[method](...params);
return { success: true, data: result };
} catch (error) {
if (error.code === 'CALL_EXCEPTION') {
return { success: false, error: 'Contract reverted' };
}
if (error.code === -32000) {
return { success: false, error: 'Execution reverted' };
}
throw error;
}
}
Best Practices
- Always specify gas limit for complex calls
- Cache results to minimize RPC calls
- Use multicall for batch operations
- Handle reverts gracefully
- Validate return data before decoding
Error Codes
Code | Message | Description |
---|---|---|
-32600 | Invalid Request | The JSON sent is not valid |
-32602 | Invalid params | Invalid method parameters |
-32603 | Internal error | Internal JSON-RPC error |
-32000 | Execution reverted | Contract execution failed |
3 | Execution reverted | EVM revert with reason |
Related Methods
- eth_estimateGas - Estimate gas for calls
- eth_getCode - Get contract bytecode
- eth_getStorageAt - Read contract storage
- eth_sendRawTransaction - Broadcast signed transactions