CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-ethersproject--contracts

Contract abstraction meta-class that enables developers to interact with Ethereum smart contracts as native JavaScript objects

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

transaction-handling.mddocs/

Transaction Handling

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.

Capabilities

Transaction Overrides

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..."]
    }
  ]
});

Gas Estimation

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")
  }
);

Transaction Population

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...

Read-Only Calls

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);
}

Enhanced Transaction Responses

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);
}

Direct Function Access

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

docs

contract-deployment.md

contract-interaction.md

event-management.md

index.md

transaction-handling.md

tile.json