EVM Integration
Overview
The Node.js SDK provides seamless integration with Ethereum Virtual Machine (EVM) compatible blockchains including Ethereum, Polygon, Binance Smart Chain, Arbitrum, Optimism, and more.
Supported EVM Chains
Blockchain | Chain ID | RPC Endpoint |
---|---|---|
Ethereum Mainnet | 0x1 | https://rpc.ankr.com/eth |
Ethereum Goerli | 0x5 | https://rpc.ankr.com/eth_goerli |
Polygon Mainnet | 0x89 | https://rpc.ankr.com/polygon |
Polygon Mumbai | 0x80001 | https://rpc.ankr.com/polygon_mumbai |
BSC Mainnet | 0x38 | https://bsc-dataseed.binance.org |
BSC Testnet | 0x61 | https://data-seed-prebsc-1-s1.binance.org:8545 |
Arbitrum One | 0xa4b1 | https://arb1.arbitrum.io/rpc |
Optimism | 0xa | https://mainnet.optimism.io |
Integration with Ethers.js
Basic Setup
const { Web3Auth } = require('@web3auth/node-sdk')
const { ethers } = require('ethers')
// Initialize Web3Auth
const web3auth = new Web3Auth({
clientId: 'YOUR_CLIENT_ID',
web3AuthNetwork: 'sapphire_mainnet',
})
await web3auth.init()
// Authenticate user
const provider = await web3auth.connect({
verifier: 'my-custom-verifier',
verifierId: 'user@example.com',
idToken: 'JWT_TOKEN',
chainId: '0x1', // Ethereum mainnet
})
// Get private key and create wallet
const privateKey = await provider.request({ method: 'eth_private_key' })
const wallet = new ethers.Wallet(privateKey)
// Connect to RPC provider
const rpcProvider = new ethers.providers.JsonRpcProvider('https://rpc.ankr.com/eth')
const connectedWallet = wallet.connect(rpcProvider)
console.log('Wallet Address:', await connectedWallet.getAddress())
Send Transaction
async function sendTransaction(toAddress, amount) {
try {
// Create transaction
const tx = {
to: toAddress,
value: ethers.utils.parseEther(amount),
gasLimit: 21000,
}
// Send transaction
const txResponse = await connectedWallet.sendTransaction(tx)
console.log('Transaction Hash:', txResponse.hash)
// Wait for confirmation
const receipt = await txResponse.wait()
console.log('Transaction confirmed in block:', receipt.blockNumber)
return receipt
} catch (error) {
console.error('Transaction failed:', error.message)
throw error
}
}
// Usage
await sendTransaction('0x742d35Cc6635C0532925a3b8138341B0F7E8a4e8', '0.1')
Smart Contract Interaction
// ERC-20 Token ABI (simplified)
const erc20Abi = [
'function balanceOf(address owner) view returns (uint256)',
'function transfer(address to, uint256 amount) returns (bool)',
'function approve(address spender, uint256 amount) returns (bool)',
'function symbol() view returns (string)',
'function decimals() view returns (uint8)',
]
async function interactWithERC20(tokenAddress) {
// Create contract instance
const tokenContract = new ethers.Contract(tokenAddress, erc20Abi, connectedWallet)
// Get token info
const symbol = await tokenContract.symbol()
const decimals = await tokenContract.decimals()
console.log(`Token: ${symbol}, Decimals: ${decimals}`)
// Get balance
const balance = await tokenContract.balanceOf(connectedWallet.address)
console.log('Token Balance:', ethers.utils.formatUnits(balance, decimals))
// Transfer tokens
const transferTx = await tokenContract.transfer(
'0x742d35Cc6635C0532925a3b8138341B0F7E8a4e8',
ethers.utils.parseUnits('10', decimals)
)
await transferTx.wait()
console.log('Transfer completed:', transferTx.hash)
}
// Usage with USDC on Ethereum
await interactWithERC20('0xA0b86a33E6441E51DBF5c4dF02a7b29fAdab0215')
Integration with Viem
Basic Setup
const { createWalletClient, createPublicClient, http } = require('viem')
const { privateKeyToAccount } = require('viem/accounts')
const { mainnet, polygon } = require('viem/chains')
// Get private key from Web3Auth
const privateKey = await provider.request({ method: 'eth_private_key' })
// Create account
const account = privateKeyToAccount(privateKey)
// Create wallet client
const walletClient = createWalletClient({
account,
chain: mainnet,
transport: http('https://rpc.ankr.com/eth'),
})
// Create public client for reading
const publicClient = createPublicClient({
chain: mainnet,
transport: http('https://rpc.ankr.com/eth'),
})
console.log('Account Address:', account.address)
Send Transaction with Viem
const { parseEther, formatEther } = require('viem')
async function sendTransactionViem(toAddress, amount) {
try {
// Get current balance
const balance = await publicClient.getBalance({
address: account.address,
})
console.log('Current Balance:', formatEther(balance), 'ETH')
// Send transaction
const hash = await walletClient.sendTransaction({
to: toAddress,
value: parseEther(amount),
})
console.log('Transaction Hash:', hash)
// Wait for confirmation
const receipt = await publicClient.waitForTransactionReceipt({ hash })
console.log('Transaction confirmed in block:', receipt.blockNumber)
return receipt
} catch (error) {
console.error('Transaction failed:', error.message)
throw error
}
}
Smart Contract with Viem
const { getContract, parseUnits, formatUnits } = require('viem')
// ERC-20 ABI
const erc20Abi = [
{
inputs: [{ name: 'owner', type: 'address' }],
name: 'balanceOf',
outputs: [{ name: '', type: 'uint256' }],
stateMutability: 'view',
type: 'function',
},
{
inputs: [
{ name: 'to', type: 'address' },
{ name: 'amount', type: 'uint256' },
],
name: 'transfer',
outputs: [{ name: '', type: 'bool' }],
stateMutability: 'nonpayable',
type: 'function',
},
] as const
async function erc20WithViem(tokenAddress) {
// Create contract instance
const contract = getContract({
address: tokenAddress,
abi: erc20Abi,
publicClient,
walletClient,
})
// Read balance
const balance = await contract.read.balanceOf([account.address])
console.log('Token Balance:', formatUnits(balance, 18))
// Write operation
const hash = await contract.write.transfer([
'0x742d35Cc6635C0532925a3b8138341B0F7E8a4e8',
parseUnits('10', 18),
])
const receipt = await publicClient.waitForTransactionReceipt({ hash })
console.log('Transfer completed:', receipt.transactionHash)
}
Multi-Chain Support
Chain Switching
async function connectToChain(chainId, authParams) {
// Connect to specific chain (stateless)
const provider = await web3auth.connect({
...authParams,
chainId,
})
return provider
}
// Connect to Polygon
const polygonProvider = await connectToChain('0x89', {
verifier: 'my-custom-verifier',
verifierId: 'user@example.com',
idToken: 'JWT_TOKEN',
})
Multi-Chain Wallet Class
class MultiChainEVMWallet {
constructor(clientId) {
this.web3auth = new Web3Auth({
clientId,
web3AuthNetwork: 'sapphire_mainnet',
})
this.wallets = new Map()
}
async initialize() {
await this.web3auth.init()
}
async connectToChain(chainId, chainConfig) {
// Connect to specific chain
const provider = await this.web3auth.connect({
verifier: 'my-custom-verifier',
verifierId: 'user@example.com',
idToken: 'JWT_TOKEN',
chainId,
})
// Create wallet for this chain
const privateKey = await provider.request({ method: 'eth_private_key' })
const wallet = new ethers.Wallet(privateKey)
const connectedWallet = wallet.connect(new ethers.providers.JsonRpcProvider(chainConfig.rpcUrl))
this.wallets.set(chainId, {
provider,
wallet: connectedWallet,
config: chainConfig,
})
return connectedWallet
}
getWallet(chainId) {
const walletData = this.wallets.get(chainId)
return walletData ? walletData.wallet : null
}
async getBalances() {
const balances = {}
for (const [chainId, walletData] of this.wallets) {
const balance = await walletData.wallet.getBalance()
balances[chainId] = {
balance: ethers.utils.formatEther(balance),
address: walletData.wallet.address,
network: walletData.config.name,
}
}
return balances
}
}
// Usage
const multiWallet = new MultiChainEVMWallet('YOUR_CLIENT_ID')
await multiWallet.initialize()
// Connect to multiple chains
await multiWallet.connectToChain('0x1', {
name: 'Ethereum',
rpcUrl: 'https://rpc.ankr.com/eth',
})
await multiWallet.connectToChain('0x89', {
name: 'Polygon',
rpcUrl: 'https://rpc.ankr.com/polygon',
})
const balances = await multiWallet.getBalances()
console.log('Multi-chain balances:', balances)
Gas Management
Estimate Gas
async function estimateAndSendTransaction(toAddress, amount) {
const tx = {
to: toAddress,
value: ethers.utils.parseEther(amount),
}
// Estimate gas
const gasEstimate = await connectedWallet.estimateGas(tx)
console.log('Estimated Gas:', gasEstimate.toString())
// Get gas price
const gasPrice = await connectedWallet.getGasPrice()
console.log('Gas Price:', ethers.utils.formatUnits(gasPrice, 'gwei'), 'gwei')
// Add gas settings to transaction
tx.gasLimit = gasEstimate.mul(120).div(100) // Add 20% buffer
tx.gasPrice = gasPrice
// Send transaction
const txResponse = await connectedWallet.sendTransaction(tx)
return txResponse
}
EIP-1559 (Type 2) Transactions
async function sendEIP1559Transaction(toAddress, amount) {
// Get fee data
const feeData = await connectedWallet.getFeeData()
const tx = {
to: toAddress,
value: ethers.utils.parseEther(amount),
type: 2, // EIP-1559
maxFeePerGas: feeData.maxFeePerGas,
maxPriorityFeePerGas: feeData.maxPriorityFeePerGas,
}
const txResponse = await connectedWallet.sendTransaction(tx)
return txResponse
}
Error Handling
async function robustEVMTransaction(toAddress, amount) {
try {
// Check balance first
const balance = await connectedWallet.getBalance()
const amountWei = ethers.utils.parseEther(amount)
if (balance.lt(amountWei)) {
throw new Error('Insufficient balance')
}
// Send transaction with retries
let retries = 3
while (retries > 0) {
try {
const tx = await sendTransaction(toAddress, amount)
return tx
} catch (error) {
retries--
if (error.code === 'NONCE_EXPIRED' && retries > 0) {
console.log('Nonce expired, retrying...')
continue
}
throw error
}
}
} catch (error) {
console.error('EVM transaction failed:', error.message)
throw error
}
}