Transaction management including overrides, gas estimation, and transaction population. Provides comprehensive control over transaction parameters with support for EIP-1559, access lists, and custom data.
Control transaction parameters through override objects.
/**
* Basic transaction overrides for gas and execution parameters
*/
interface Overrides {
/** Gas limit for transaction execution */
gasLimit?: BigNumberish | Promise<BigNumberish>;
/** Gas price (legacy transactions) */
gasPrice?: BigNumberish | Promise<BigNumberish>;
/** Maximum fee per gas (EIP-1559) */
maxFeePerGas?: BigNumberish | Promise<BigNumberish>;
/** Maximum priority fee per gas (EIP-1559) */
maxPriorityFeePerGas?: BigNumberish | Promise<BigNumberish>;
/** Transaction nonce */
nonce?: BigNumberish | Promise<BigNumberish>;
/** Transaction type (0 = legacy, 1 = EIP-2930, 2 = EIP-1559) */
type?: number;
/** EIP-2930 access list */
accessList?: AccessListish;
/** Custom data for L2/sidechain compatibility */
customData?: Record<string, any>;
/** Enable CCIP-Read (EIP-3668) support */
ccipReadEnabled?: boolean;
}
/**
* Transaction overrides with value field for payable functions
*/
interface PayableOverrides extends Overrides {
/** Ether value to send with transaction */
value?: BigNumberish | Promise<BigNumberish>;
}
/**
* Transaction overrides for read-only calls
*/
interface CallOverrides extends PayableOverrides {
/** Block tag for historical state queries */
blockTag?: BlockTag | Promise<BlockTag>;
/** Address to simulate call from */
from?: string | Promise<string>;
}Usage Examples:
import { Contract } from "@ethersproject/contracts";
import { parseEther, parseUnits } from "@ethersproject/units";
const contract = new Contract(address, abi, signer);
// Basic transaction with gas overrides
await contract.transfer("0x...", parseEther("1.0"), {
gasLimit: 21000,
gasPrice: parseUnits("20", "gwei")
});
// EIP-1559 transaction
await contract.transfer("0x...", parseEther("1.0"), {
maxFeePerGas: parseUnits("30", "gwei"),
maxPriorityFeePerGas: parseUnits("2", "gwei")
});
// Payable function with value
await contract.deposit({
value: parseEther("1.0"),
gasLimit: 100000
});
// Read call with historical state
const balance = await contract.balanceOf("0x...", {
blockTag: 12000000,
from: "0x..." // Simulate call from different address
});
// Transaction with access list (EIP-2930)
await contract.complexFunction("param1", "param2", {
type: 1,
accessList: [
{
address: "0x...",
storageKeys: ["0x..."]
}
]
});Estimate gas required for contract method calls.
/**
* Gas estimation methods for all contract functions
* Accessible via contract.estimateGas[methodName]
*/
readonly estimateGas: { [name: string]: ContractFunction<BigNumber> };Usage Examples:
// Estimate gas for specific method
const gasEstimate = await contract.estimateGas.transfer("0x...", parseEther("1.0"));
console.log("Estimated gas:", gasEstimate.toString());
// Estimate with overrides
const gasWithOverrides = await contract.estimateGas.transfer(
"0x...",
parseEther("1.0"),
{ value: parseEther("0.1") } // If transfer is payable
);
// Use estimate in actual transaction
await contract.transfer("0x...", parseEther("1.0"), {
gasLimit: gasEstimate.mul(120).div(100) // Add 20% buffer
});
// Estimate complex function with parameters
const complexGas = await contract.estimateGas.complexFunction(
"param1",
["array", "values"],
{ nested: "object" },
{
from: wallet.address, // Override sender for estimation
value: parseEther("1.0")
}
);Prepare transactions without sending them.
/**
* Transaction population methods for all contract functions
* Accessible via contract.populateTransaction[methodName]
*/
readonly populateTransaction: { [name: string]: ContractFunction<PopulatedTransaction> };
/**
* Populated transaction object ready for signing and sending
*/
interface PopulatedTransaction {
/** Recipient address */
to?: string;
/** Sender address */
from?: string;
/** Transaction nonce */
nonce?: number;
/** Gas limit */
gasLimit?: BigNumber;
/** Gas price (legacy) */
gasPrice?: BigNumber;
/** Transaction data (encoded function call) */
data?: string;
/** Ether value */
value?: BigNumber;
/** Chain ID */
chainId?: number;
/** Transaction type */
type?: number;
/** Access list */
accessList?: AccessList;
/** Max fee per gas (EIP-1559) */
maxFeePerGas?: BigNumber;
/** Max priority fee per gas (EIP-1559) */
maxPriorityFeePerGas?: BigNumber;
/** Custom data */
customData?: Record<string, any>;
/** CCIP-Read enabled flag */
ccipReadEnabled?: boolean;
}Usage Examples:
// Populate transaction without sending
const populatedTx = await contract.populateTransaction.transfer(
"0x...",
parseEther("1.0")
);
console.log("Transaction data:", populatedTx.data);
console.log("To address:", populatedTx.to);
// Add custom overrides to populated transaction
populatedTx.gasLimit = BigNumber.from(25000);
populatedTx.gasPrice = parseUnits("25", "gwei");
// Send populated transaction manually
const sentTx = await signer.sendTransaction(populatedTx);
await sentTx.wait();
// Use with multisig or custom signing
const multisigTx = await contract.populateTransaction.adminFunction("param");
// Send to multisig contract for signing...
// Batch multiple transactions
const tx1 = await contract.populateTransaction.method1("param1");
const tx2 = await contract.populateTransaction.method2("param2");
// Submit to batch transaction contract...Call contract methods without sending transactions (for view/pure functions).
/**
* Read-only method calls for all contract functions
* Accessible via contract.callStatic[methodName]
*/
readonly callStatic: { [name: string]: ContractFunction };Usage Examples:
// Force read-only call (even for non-view functions)
const result = await contract.callStatic.someFunction("param");
// Read-only call with block tag
const historicalBalance = await contract.callStatic.balanceOf("0x...", {
blockTag: 12000000
});
// Simulate transaction without sending
const simulationResult = await contract.callStatic.transfer("0x...", parseEther("1.0"), {
from: "0x..." // Simulate from different address
});
// Check if transaction would succeed
try {
await contract.callStatic.complexFunction("param");
console.log("Transaction would succeed");
} catch (error) {
console.log("Transaction would fail:", error.reason);
}Contract transactions return enhanced response objects with event decoding.
/**
* Enhanced transaction response with contract-specific wait method
*/
interface ContractTransaction extends TransactionResponse {
/**
* Wait for transaction confirmation with automatic event decoding
* @param confirmations - Number of confirmations to wait for
* @returns Promise resolving to ContractReceipt with decoded events
*/
wait(confirmations?: number): Promise<ContractReceipt>;
}
/**
* Enhanced transaction receipt with decoded contract events
*/
interface ContractReceipt extends TransactionReceipt {
/** Array of decoded contract events from transaction */
events?: Array<Event>;
}Usage Examples:
// Send transaction and wait for confirmation
const tx = await contract.transfer("0x...", parseEther("1.0"));
console.log("Transaction hash:", tx.hash);
// Wait for confirmation with event decoding
const receipt = await tx.wait();
// Access decoded events
if (receipt.events) {
for (const event of receipt.events) {
if (event.event === "Transfer") {
console.log("Transfer event:", event.args);
}
}
}
// Wait for multiple confirmations
const confirmedReceipt = await tx.wait(3);
// Access event utility methods
if (receipt.events && receipt.events.length > 0) {
const event = receipt.events[0];
// Get additional blockchain data
const block = await event.getBlock();
const transaction = await event.getTransaction();
console.log("Block timestamp:", block.timestamp);
console.log("Transaction from:", transaction.from);
}Access contract functions through multiple interfaces for different use cases.
/**
* Direct access to contract functions without result processing
* Accessible via contract.functions[methodName]
*/
readonly functions: { [name: string]: ContractFunction };Usage Examples:
// Direct function access (returns raw result)
const rawResult = await contract.functions.balanceOf("0x...");
console.log("Raw result:", rawResult); // Array format
// Compare with processed result
const processedResult = await contract.balanceOf("0x...");
console.log("Processed result:", processedResult); // Single value if function returns one value
// Multiple return values
const [reserve0, reserve1, timestamp] = await contract.functions.getReserves();
console.log("Reserve 0:", reserve0.toString());
console.log("Reserve 1:", reserve1.toString());
console.log("Timestamp:", timestamp.toString());
// Access function that conflicts with contract properties
const result = await contract.functions["name"](); // If "name" conflicts with contract.name property