@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:
- Auth vs. Wallet vs. Signer - Understanding the three-layer architecture
- Tutorial - Using and extending signers
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:
- Network Implementation Guide - Comprehensive guide for implementing blockchain network support
- Workflow Builder and Plugins Guide - Plugin-based transaction workflow architecture for extensible transaction building
Interchain JavaScript Stack ⚛️
A unified toolkit for building applications and smart contracts in the Interchain ecosystem
Category | Tools | Description |
---|---|---|
Chain Information | Chain 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 Connectors | Interchain 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 Clients | InterchainJS (opens in a new tab), CosmJS (opens in a new tab) | A single, universal signing interface for any network |
SDK Clients | Telescope (opens in a new tab) | Your Frontend Companion for Building with TypeScript with Cosmos SDK Modules. |
Starter Kits | Create 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 Kits | Interchain UI (opens in a new tab) | The Interchain Design System, empowering developers with a flexible, easy-to-use UI kit. |
Testing Frameworks | Starship (opens in a new tab) | Unified Testing and Development for the Interchain. |
TypeScript Smart Contracts | Create Hyperweb App (opens in a new tab) | Build and deploy full-stack blockchain applications with TypeScript |
CosmWasm Contracts | CosmWasm 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.