Ethers.js v5 has dozens of breaking changes when upgrading to v6. BigNumber is gone, provider names changed, utility functions moved, and contract patterns restructured. Doing this by hand across hundreds of files takes days.
I built a codemod toolkit using jssg (JavaScript ast-grep) that automates 95% of this migration with one command.
Quick Start
npx codemod ethers-v5-to-v6-codemod
The Problem
Thousands of DeFi projects are still on ethers v5. The migration is painful not because any single change is hard, but because of sheer volume across hundreds of files. Simple regex fails on edge cases. The ecosystem needed a structural solution.
The Approach
12 jssg (JavaScript ast-grep) transforms orchestrated via workflow.yaml. jssg parses code into an AST — so replacements are structurally exact and never touch patterns inside string literals or comments. Zero false positives guaranteed.
What Gets Automated
- Utils functions — ethers.utils.formatEther, parseEther, formatUnits, arrayify, hexlify, and 10 more
- BigNumber to BigInt — BigNumber.from(x) to BigInt(x) with smart scope-aware detection
- Provider renames — ethers.providers.Web3Provider to ethers.BrowserProvider
- Crypto utils — keccak256, sha256, toUtf8Bytes, solidityKeccak256
- callStatic to staticCall — contract.callStatic.foo() to contract.foo.staticCall()
- Contract address — contract.address to contract.target
- Broadcast transaction — provider.sendTransaction(hex) to provider.broadcastTransaction(hex)
- Signature class — splitSignature, joinSignature, verifyMessage, recoverAddress
- Import cleanup — removes deprecated BigNumber and providers imports
- Gas price — provider.getGasPrice() to provider.getFeeData()
- Contract methods — estimateGas, populateTransaction, functions namespace
- Sub-package imports — @ethersproject/* to ethers
Real World Proof
Tested on thallo-io/ethers-js-cheatsheet — a real open source TypeScript DeFi project.
Result: 6 files transformed, 0 errors, 0 false positives, 1.266 seconds
Uniswap quote script before:
const amountIn = ethers.utils.parseEther("1");
const priceQuote = await uni.callStatic.quoteExactInputSingle(WETH9, DAI, fee, amountIn, sqrtPriceLimitX96);
console.log(ethers.utils.formatEther(priceQuote));
After:
const amountIn = ethers.parseEther("1");
const priceQuote = await uni.quoteExactInputSingle.staticCall(WETH9, DAI, fee, amountIn, sqrtPriceLimitX96);
console.log(ethers.formatEther(priceQuote));
Three patterns fixed automatically in one pass.
Coverage Breakdown
- Automated by jssg transforms: ~95%
- AI following AI-INSTRUCTIONS.md: ~4%
- Manual review: ~1%
Links
- GitHub: https://github.com/DeewakarBora/ethers-v5-to-v6-codemod
- Codemod registry: https://app.codemod.com/registry/ethers-v5-to-v6-codemod
- DoraHacks: https://dorahacks.io/buidl/42646
Top comments (0)