Web3 module to interact with the Ethereum blockchain and smart contracts.
67
The smart contract interaction functionality provides methods to execute contract calls, estimate gas consumption, create access lists, and interact with smart contracts without state changes.
Executes a read-only call to a smart contract method without creating a transaction on the blockchain.
call(transaction?: TransactionCall, blockNumber?: BlockNumberOrTag, returnFormat?: DataFormat): Promise<Bytes>;Parameters:
transaction: Transaction call object with contract address, method data, and parametersblockNumber: Block number or tag to execute call against (defaults to "latest")returnFormat: Output format configurationUsage Example:
// Simple contract call - get total supply of an ERC20 token
const totalSupplyCall = {
to: "0x1234567890123456789012345678901234567890", // token contract address
data: "0x18160ddd" // totalSupply() method selector
};
const result = await eth.call(totalSupplyCall);
console.log("Total supply (raw):", result);
// Contract call with parameters - get balance of specific address
import { encodeFunctionCall } from "web3-eth-abi";
const balanceOfCall = {
to: "0x1234567890123456789012345678901234567890",
data: encodeFunctionCall({
name: "balanceOf",
type: "function",
inputs: [{ name: "owner", type: "address" }]
}, ["0x742d35Cc6634C0532925a3b8D7389Fc3C1b6c5E"])
};
const balance = await eth.call(balanceOfCall);
console.log("Token balance:", balance);
// Historical state query
const historicalBalance = await eth.call(balanceOfCall, 15000000);Estimates the amount of gas required to execute a transaction or contract call.
estimateGas(transaction?: TransactionCall, blockNumber?: BlockNumberOrTag, returnFormat?: DataFormat): Promise<Numbers>;Usage Example:
// Estimate gas for token transfer
const transferGasEstimate = await eth.estimateGas({
from: "0x742d35Cc6634C0532925a3b8D7389Fc3C1b6c5E",
to: "0x1234567890123456789012345678901234567890", // token contract
data: encodeFunctionCall({
name: "transfer",
type: "function",
inputs: [
{ name: "to", type: "address" },
{ name: "amount", type: "uint256" }
]
}, [
"0x8ba1f109551bD432803012645Hac136c1c1b6c5E", // recipient
"1000000000000000000" // 1 token (assuming 18 decimals)
])
});
console.log(`Estimated gas for transfer: ${transferGasEstimate}`);
// Estimate gas for contract deployment
const deploymentGasEstimate = await eth.estimateGas({
from: "0x742d35Cc6634C0532925a3b8D7389Fc3C1b6c5E",
data: "0x608060405234801561001057600080fd5b50..." // contract bytecode
});
console.log(`Estimated gas for deployment: ${deploymentGasEstimate}`);
// Add buffer to gas estimate (common practice)
const gasWithBuffer = Math.floor(Number(transferGasEstimate) * 1.2); // 20% bufferGenerates an access list for EIP-2930 transactions to reduce gas costs by pre-declaring storage access.
createAccessList(transaction?: TransactionForAccessList, blockNumber?: BlockNumberOrTag, returnFormat?: DataFormat): Promise<AccessListResult>;Usage Example:
// Create access list for token transfer
const accessListResult = await eth.createAccessList({
from: "0x742d35Cc6634C0532925a3b8D7389Fc3C1b6c5E",
to: "0x1234567890123456789012345678901234567890",
data: encodeFunctionCall({
name: "transfer",
type: "function",
inputs: [
{ name: "to", type: "address" },
{ name: "amount", type: "uint256" }
]
}, [
"0x8ba1f109551bD432803012645Hac136c1c1b6c5E",
"1000000000000000000"
])
});
console.log("Access list:", accessListResult.accessList);
console.log("Gas used with access list:", accessListResult.gasUsed);
// Use access list in transaction to save gas
const receipt = await eth.sendTransaction({
from: "0x742d35Cc6634C0532925a3b8D7389Fc3C1b6c5E",
to: "0x1234567890123456789012345678901234567890",
data: encodeFunctionCall(/* ... */),
accessList: accessListResult.accessList,
type: 1 // EIP-2930 transaction type
});// Common ERC20 interactions
class ERC20Helper {
constructor(private eth: Web3Eth, private tokenAddress: Address) {}
async totalSupply(): Promise<string> {
const result = await this.eth.call({
to: this.tokenAddress,
data: "0x18160ddd" // totalSupply()
});
return result;
}
async balanceOf(owner: Address): Promise<string> {
const result = await this.eth.call({
to: this.tokenAddress,
data: encodeFunctionCall({
name: "balanceOf",
type: "function",
inputs: [{ name: "owner", type: "address" }]
}, [owner])
});
return result;
}
async estimateTransfer(from: Address, to: Address, amount: string): Promise<number> {
const gasEstimate = await this.eth.estimateGas({
from,
to: this.tokenAddress,
data: encodeFunctionCall({
name: "transfer",
type: "function",
inputs: [
{ name: "to", type: "address" },
{ name: "amount", type: "uint256" }
]
}, [to, amount])
});
return Number(gasEstimate);
}
}// Query multiple contract states efficiently
async function getContractStates(contractAddress: Address) {
// Prepare multiple calls
const calls = [
{ to: contractAddress, data: "0x18160ddd" }, // totalSupply()
{ to: contractAddress, data: "0x313ce567" }, // decimals()
{ to: contractAddress, data: "0x95d89b41" }, // symbol()
{ to: contractAddress, data: "0x06fdde03" } // name()
];
// Execute all calls in parallel
const results = await Promise.all(
calls.map(call => eth.call(call))
);
return {
totalSupply: results[0],
decimals: results[1],
symbol: results[2],
name: results[3]
};
}// Helper for common view function patterns
async function callViewFunction(
contractAddress: Address,
functionAbi: any,
params: any[] = [],
blockNumber?: BlockNumberOrTag
) {
const data = encodeFunctionCall(functionAbi, params);
return await eth.call({
to: contractAddress,
data
}, blockNumber);
}
// Usage example
const ownerResult = await callViewFunction(
"0x1234567890123456789012345678901234567890",
{
name: "owner",
type: "function",
inputs: [],
outputs: [{ name: "", type: "address" }]
}
);// Handle contract call errors
async function safeContractCall(transaction: TransactionCall) {
try {
const result = await eth.call(transaction);
return { success: true, data: result };
} catch (error) {
// Check if it's a revert with reason
if (error.message.includes("execution reverted")) {
return {
success: false,
error: "Contract execution reverted",
details: error.message
};
}
// Other errors (invalid address, network issues, etc.)
return {
success: false,
error: "Call failed",
details: error.message
};
}
}interface TransactionCall {
from?: Address;
to: Address;
gas?: Numbers;
gasPrice?: Numbers;
maxFeePerGas?: Numbers;
maxPriorityFeePerGas?: Numbers;
value?: Numbers;
data?: Bytes;
type?: Numbers;
accessList?: AccessList;
}
interface TransactionForAccessList {
from?: Address;
to?: Address;
gas?: Numbers;
gasPrice?: Numbers;
maxFeePerGas?: Numbers;
maxPriorityFeePerGas?: Numbers;
value?: Numbers;
data?: Bytes;
}
interface AccessList {
address: Address;
storageKeys: HexString32Bytes[];
}
interface AccessListResult {
accessList: AccessList[];
gasUsed: HexString;
}
type Address = HexString20Bytes;
type Numbers = HexString | number | bigint;
type Bytes = HexString;
type BlockNumberOrTag = Numbers | "latest" | "earliest" | "pending" | "safe" | "finalized";
interface DataFormat {
number: NumberFormat;
bytes: BytesFormat;
}Install with Tessl CLI
npx tessl i tessl/npm-web3-ethdocs
evals
scenario-1
scenario-2
scenario-3
scenario-4
scenario-5
scenario-6
scenario-7
scenario-8
scenario-9
scenario-10