InterchainJS
Networks
Ethereum
Overview

@interchainjs/ethereum

Welcome to the InterchainJS Ethereum tutorial! This guide will help you quickly get started with sending transactions, interacting with smart contracts, and handling Ethereum utilities using the @interchainjs/ethereum package. Whether you're building backend services or frontend dApps, you'll find practical examples and tips below. Let's dive in! ✨


Overview

Transaction codec and client to communicate with the Ethereum blockchain.


Installation

npm install @interchainjs/ethereum

Usage

Query Client

The Ethereum Query Client provides a comprehensive interface for querying Ethereum blockchain data using JSON-RPC.

Basic Setup

import { createEthereumQueryClient } from "@interchainjs/ethereum";
 
// Create a query client
const queryClient = await createEthereumQueryClient("https://eth.llamarpc.com");
 
// Or with options
const queryClient = await createEthereumQueryClient("https://eth.llamarpc.com", {
  timeout: 30000,
  headers: {
    'User-Agent': 'MyApp/1.0.0'
  }
});

Basic Information

// Get chain ID
const chainId = await queryClient.getChainId();
console.log("Chain ID:", chainId); // 1 for mainnet
 
// Get latest block number
const blockNumber = await queryClient.getBlockNumber();
console.log("Latest block:", blockNumber);
 
// Check sync status
const syncing = await queryClient.isSyncing();
console.log("Syncing:", syncing);

Block Queries

// Get latest block
const latestBlock = await queryClient.getLatestBlock();
console.log("Latest block hash:", latestBlock.hash);
 
// Get block by number
const block = await queryClient.getBlockByNumber(18000000);
console.log("Block timestamp:", block.timestamp);
 
// Get block by hash
const blockByHash = await queryClient.getBlockByHash("0x95b198e154acbfc64109dfd22d8224fe927fd8dfdedfae01587674482ba4baf3");
console.log("Block number:", blockByHash.number);
 
// Get transaction count in block
const txCount = await queryClient.getBlockTransactionCount(18000000);
console.log("Transaction count:", txCount);

Transaction Queries

// Get transaction details
const tx = await queryClient.getTransaction("0x16e199673891df518e25db2ef5320155da82a3dd71a677e7d84363251885d133");
console.log("From:", tx.from, "To:", tx.to, "Value:", tx.value);
 
// Get transaction receipt
const receipt = await queryClient.getTransactionReceipt("0x16e199673891df518e25db2ef5320155da82a3dd71a677e7d84363251885d133");
console.log("Status:", receipt.status, "Gas used:", receipt.gasUsed);
 
// Get account nonce
const nonce = await queryClient.getTransactionCount("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045");
console.log("Nonce:", nonce);

Account and Balance Queries

// Get account balance
const balance = await queryClient.getBalance("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045");
console.log("Balance:", balance.toString(), "wei");
 
// Get contract code
const code = await queryClient.getCode("0xdAC17F958D2ee523a2206206994597C13D831ec7");
console.log("Contract code length:", code.length);
 
// Get storage value
const storage = await queryClient.getStorageAt("0xdAC17F958D2ee523a2206206994597C13D831ec7", "0x0");
console.log("Storage at slot 0:", storage);

Gas and Fee Queries

// Get current gas price
const gasPrice = await queryClient.getGasPrice();
console.log("Gas price:", gasPrice.toString(), "wei");
 
// Get max priority fee (EIP-1559)
const priorityFee = await queryClient.getMaxPriorityFeePerGas();
console.log("Priority fee:", priorityFee.toString(), "wei");
 
// Get fee history
const feeHistory = await queryClient.getFeeHistory(4, 'latest', [25, 50, 75]);
console.log("Base fees:", feeHistory.baseFeePerGas);
 
// Estimate gas for transaction
const gasEstimate = await queryClient.estimateGas({
  from: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
  to: "0x0000000000000000000000000000000000000000",
  value: "0x1"
});
console.log("Gas estimate:", gasEstimate.toString());

Event Logs and Filters

// Get logs
const logs = await queryClient.getLogs({
  fromBlock: 18000000,
  toBlock: 18000100,
  address: "0xdAC17F958D2ee523a2206206994597C13D831ec7",
  topics: ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"] // Transfer event
});
console.log("Found", logs.length, "Transfer events");
 
// Create and manage filters
const filterId = await queryClient.newFilter({
  fromBlock: 'latest',
  toBlock: 'latest'
});
 
const filterLogs = await queryClient.getFilterLogs(filterId);
console.log("Filter logs:", filterLogs.length);
 
// Clean up filter
await queryClient.uninstallFilter(filterId);

WebSocket Support

import { EthereumClientFactory } from "@interchainjs/ethereum";
 
// Create WebSocket query client for real-time updates
const wsQueryClient = await EthereumClientFactory.createWebSocketQueryClient("wss://eth.llamarpc.com");
 
// Use the same interface as HTTP client
const latestBlock = await wsQueryClient.getLatestBlock();
console.log("Latest block via WebSocket:", latestBlock.number);

Error Handling

try {
  const block = await queryClient.getBlockByNumber(999999999999);
} catch (error) {
  console.error("Block not found:", error.message);
}
 
try {
  const tx = await queryClient.getTransaction("0xinvalid");
} catch (error) {
  console.error("Invalid transaction hash:", error.message);
}

Connection Management

// Check connection status
console.log("Connected:", queryClient.isConnected());
 
// Get endpoint
console.log("Endpoint:", queryClient.endpoint);
 
// Disconnect when done
await queryClient.disconnect();

Using Ethereum Signers

Creating Signers

InterchainJS provides modern Ethereum signers that implement the IUniSigner interface:

import { LegacyEthereumSigner, EIP1559EthereumSigner } from '@interchainjs/ethereum';
import { Secp256k1HDWallet } from '@interchainjs/ethereum';
import { EthereumQueryClient } from '@interchainjs/ethereum';
import { HttpRpcClient } from '@interchainjs/utils/clients';
import { EthereumAdapter } from '@interchainjs/ethereum';
 
// Create wallet from private key
const wallet = Secp256k1HDWallet.fromPrivateKey('0x...');
 
// Or create from mnemonic
const wallet = await Secp256k1HDWallet.fromMnemonic('your mnemonic phrase here');
 
// Create query client
const rpcClient = new HttpRpcClient('https://eth.llamarpc.com');
const adapter = new EthereumAdapter();
const queryClient = new EthereumQueryClient(rpcClient, adapter);
 
// Create signers
const legacySigner = new LegacyEthereumSigner(wallet, { queryClient });
const eip1559Signer = new EIP1559EthereumSigner(wallet, { queryClient });

Get Address, Balance, and Nonce

// Get addresses
const addresses = await legacySigner.getAddresses();
const address = addresses[0];
console.log("Address:", address);
 
// Get balance using query client
const balance = await queryClient.getBalance(address);
console.log("Balance (wei):", balance);
 
// Get nonce using query client
const nonce = await queryClient.getTransactionCount(address);
console.log("Nonce:", nonce);

Send Legacy and EIP-1559 Transactions

// Send a legacy transaction
const legacyResult = await legacySigner.signAndBroadcast({
  transaction: {
    to: recipientAddress,
    value: '1000000000000000', // 0.001 ETH in wei
    gasPrice: '20000000000', // 20 gwei
    gas: '21000'
  }
});
console.log("Legacy tx hash:", legacyResult.transactionHash);
 
// Send an EIP-1559 transaction
const eip1559Result = await eip1559Signer.signAndBroadcast({
  transaction: {
    to: recipientAddress,
    value: '1000000000000000', // 0.001 ETH in wei
    maxFeePerGas: '30000000000', // 30 gwei
    maxPriorityFeePerGas: '2000000000', // 2 gwei
    gas: '21000'
  }
});
console.log("EIP-1559 tx hash:", eip1559Result.transactionHash);
 
// Wait for transaction confirmation
const receipt = await eip1559Result.wait();
console.log("Transaction receipt:", receipt);

Sign and Verify a Personal Message

// Sign a personal message
const message = "Hello, Ethereum!";
const signature = await legacySigner.signPersonalMessage(message, address);
console.log("Signature:", signature);
 
// Verify the signature
const isValid = await legacySigner.verifyPersonalMessage(message, signature, address);
console.log("Signature valid:", isValid);

Estimate Gas for a Transaction

// Estimate gas for a transaction using query client
const estimatedGas = await queryClient.estimateGas({
  to: recipientAddress,
  value: '500000000000000000', // 0.5 ETH in wei
  from: address,
  data: '0x' // optional data
});
console.log("Estimated gas:", estimatedGas.toString());

Deploy a Smart Contract

// Deploy a smart contract
const bytecode = "0x..."; // compiled contract bytecode
const { txHash: deployHash, wait: deployWait } =
  await signer.sendLegacyTransactionAutoGasLimit("", 0n, bytecode);
const deployReceipt = await deployWait();
console.log("Contract deployed at:", deployReceipt.contractAddress);

Interact with a Deployed Contract (ERC20 Transfer)

// Interact with a deployed contract (transfer ERC20 tokens)
import { ContractEncoder } from "@interchainjs/ethereum/utils/ContractEncoder";
const abi = [
  /* ERC20 contract ABI */
];
const contractAddress = deployReceipt.contractAddress;
const contract = new ContractEncoder(abi);
const dataHex = contract.transfer(recipientAddress, 1000000n);
const { txHash: tokenHash, wait: tokenWait } =
  await signer.sendLegacyTransactionAutoGasLimit(contractAddress, 0n, dataHex);
const tokenReceipt = await tokenWait();
console.log("Token transfer receipt:", tokenReceipt);

Monitor Contract Events via WebSocket

// Monitor contract events via WebSocket
import { WebSocketContractMonitor } from "@interchainjs/ethereum/providers/WebSocketContractMonitor";
const wsUrl = "ws://127.0.0.1:8546";
const monitor = new WebSocketContractMonitor(contractAddress, abi, wsUrl);
await monitor.connect();
monitor.on("Transfer", (event) => {
  console.log("Transfer event:", event);
});

See more usages in the unit test (opens in a new tab)

In the frontend

Send Transaction from Browser Wallet

import { SignerFromBrowser } from "@interchainjs/ethereum/signers/SignerFromBrowser";
const signer = new SignerFromBrowser(window.ethereum);
const tx = await signer.send({
  to: recipientAddress,
  value: BigInt(10 ** 18),
});
const receipt = await tx.wait();

For more details, see this example (opens in a new tab)


Utility Functions

Denominations

Parse and Format ETH/Token Amounts

import {
  parseEther,
  formatEther,
  parseUnits,
  formatUnits
} from "@interchainjs/ethereum/utils/denominations";
 
// Parse ETH to wei
const wei: bigint = parseEther("1.5"); // 1500000000000000000n
 
// Format wei to ETH
const eth: string = formatEther(wei); // "1.5"
 
// Parse a token amount (e.g., 6 decimals)
const units: bigint = parseUnits("123.456", 6);
 
// Format back to human‐readable
const amount: string = formatUnits(units, 6); // "123.456"

Encoding

UTF-8 and Hex Conversion

import {
  utf8ToHex,
  hexToUtf8
} from "@interchainjs/ethereum/utils/encoding";
 
const hex = utf8ToHex("Hello, Ethereum!"); // "48656c6c6f2c20457468657265756d21"
const str = hexToUtf8("0x48656c6c6f");     // "Hello"

Address Utilities

Validate and Checksum Ethereum Addresses

import {
  isValidEthereumAddress,
  toChecksumAddress
} from "@interchainjs/ethereum/utils/address";
 
const addr = "0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359";
console.log(isValidEthereumAddress(addr));
// true
 
const lower = "0xfB6916095ca1df60bb79ce92ce3ea74c37c5d359";
console.log(toChecksumAddress(lower));
// "0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359"

Implementations

  • LegacyEthereumSigner: Pre-EIP-1559 transactions using gasPrice (@interchainjs/ethereum)
  • EIP1559EthereumSigner: EIP-1559 transactions with dynamic fees (@interchainjs/ethereum)
  • Secp256k1HDWallet: HD wallet implementation for Ethereum networks (@interchainjs/ethereum)
  • EthereumQueryClient: Query client for Ethereum RPC endpoints (@interchainjs/ethereum)

Legacy Support

  • SignerFromPrivateKey: Original implementation (maintained for backward compatibility)
  • SignerFromBrowser: Browser wallet integration (maintained for backward compatibility)

For Developers

Understanding the Architecture

To understand how the Ethereum network implementation fits into the broader InterchainJS architecture:

Implementing Custom Networks

If you're implementing support for a new Ethereum-compatible network or want to understand the architectural patterns used in this implementation:

Interchain JavaScript Stack ⚛️

A unified toolkit for building applications and smart contracts in the Interchain ecosystem

CategoryToolsDescription
Chain InformationChain Registry (opens in a new tab), Utils (opens in a new tab), Client (opens in a new tab)Everything from token symbols, logos, and IBC denominations for all assets you want to support in your application.
Wallet ConnectorsInterchain Kit (opens in a new tab), Cosmos Kit (opens in a new tab)Experience the convenience of connecting with a variety of web3 wallets through a single, streamlined interface.
Signing ClientsInterchainJS (opens in a new tab), CosmJS (opens in a new tab)A single, universal signing interface for any network
SDK ClientsTelescope (opens in a new tab)Your Frontend Companion for Building with TypeScript with Cosmos SDK Modules.
Starter KitsCreate Interchain App (opens in a new tab), Create Cosmos App (opens in a new tab)Set up a modern Interchain app by running one command.
UI KitsInterchain UI (opens in a new tab)The Interchain Design System, empowering developers with a flexible, easy-to-use UI kit.
Testing FrameworksStarship (opens in a new tab)Unified Testing and Development for the Interchain.
TypeScript Smart ContractsCreate Hyperweb App (opens in a new tab)Build and deploy full-stack blockchain applications with TypeScript
CosmWasm ContractsCosmWasm TS Codegen (opens in a new tab)Convert your CosmWasm smart contracts into dev-friendly TypeScript classes.

Credits

🛠 Built by Hyperweb (formerly Cosmology) — if you like our tools, please checkout and contribute to our github ⚛️ (opens in a new tab)

Disclaimer

AS DESCRIBED IN THE LICENSES, THE SOFTWARE IS PROVIDED “AS IS”, AT YOUR OWN RISK, AND WITHOUT WARRANTIES OF ANY KIND.

No developer or entity involved in creating this software will be liable for any claims or damages whatsoever associated with your use, inability to use, or your interaction with other users of the code, including any direct, indirect, incidental, special, exemplary, punitive or consequential damages, or loss of profits, cryptocurrencies, tokens, or anything else of value.