ethers-upgrade-v6
v0.1.0
Published
An automated codemod to migrate ethers.js v5 to v6
Maintainers
Readme
ethers-upgrade-v6
Codemod pipeline for migrating ethers.js v5 codebases to v6-compatible APIs.
Table of Contents
- Overview
- How It Works
- Pipeline Order
- Transform Coverage
- Manual Follow-Up TODOs
- Usage
- Pipeline Options
- Project Structure
- Development
- Safety and Limitations
Overview
This repository contains a composed jscodeshift transform that runs multiple migration steps in a deterministic order.
Its goal is to automate common v5-to-v6 changes while staying conservative for ambiguous patterns.
The codemod entrypoint is src/index.ts, and the workflow integration points at that file via workflow.yaml.
How It Works
The main transform in src/index.ts:
- Executes each transform step sequentially on the latest source.
- Tracks whether each step changed the file.
- Produces per-step and final summary reports (configurable).
- Fails fast with enriched error context (
step name + file path) if a step throws.
If no step changes a file, the original source is returned unchanged.
Pipeline Order
Transforms run in this exact order:
normalizeImportsbignumber-to-bigintproviderscontractsnormalizeUtilsconstants
Ordering matters because earlier transforms normalize imports and namespaces that later transforms depend on.
Transform Coverage
1) normalizeImports
Normalizes and consolidates legacy imports:
- Rewrites subpath imports to root
ethers:ethers/lib/*,ethers/lib.esm/*,ethers/utils*,ethers/providers*@ethersproject/*
- Removes deprecated root namespace imports from
ethers:providers,utils,BigNumber,constants,errors,logger,wordlists
- Merges duplicate root
ethersnamed imports, preserving type vs value import separation. - Keeps side-effect/default/namespace import declarations intact.
2) bignumber-to-bigint
Migrates safe constructor patterns:
ethers.BigNumber.from(x)->BigInt(x)BigNumber.from(x)->BigInt(x)(when bound to theethersimport)
For chained BigNumber flows (for example .pow(), .add() chains), it does not auto-rewrite logic and instead adds:
TODO: v6-bigint manual BigNumber chain migration
3) providers
Applies provider-related migrations:
- Flattens
ethers.providers.*->ethers.* - Renames:
Web3Provider->BrowserProviderStaticJsonRpcProvider->JsonRpcProvider
- Rewrites
new StaticJsonRpcProvider(url, network?, options?)to v6 constructor shape and injectsstaticNetworksafely. - Rewrites likely provider calls:
sendTransaction(...)->broadcastTransaction(...)await provider.getGasPrice()->(await provider.getFeeData()).gasPrice
- Rewrites fee-data patterns:
lastBaseFeePerGas->maxFeePerGasmaxPriorityFeePerGas + lastBaseFeePerGas(and.add(...)variant) ->maxFeePerGas
- Adds TODO when
getSigner()appears un-awaited on likely provider objects:TODO: v6-provider getSigner() is now async; add await
4) contracts
Migrates removed contract method-bucket calls:
contract.functions.foo(args)->contract.foo(args)contract.callStatic.foo(args)->contract.foo.staticCall(args)contract.estimateGas.foo(args)->contract.foo.estimateGas(args)contract.populateTransaction.foo(args)->contract.foo.populateTransaction(args)
Uses conservative receiver heuristics (contract, *Contract, this.contract) and skips computed access forms.
5) normalizeUtils
Normalizes ethers.utils usage:
- Flattens
ethers.utils.<name>->ethers.<name>where supported. - Applies known utility renames:
hexDataSlice->dataSlicehexZeroPad->zeroPadValuehexValue->toQuantityarrayify->getBytesformatBytes32String->encodeBytes32StringparseBytes32String->decodeBytes32StringsolidityPack->solidityPackedsolidityKeccak256->solidityPackedKeccak256soliditySha256->solidityPackedSha256
- Signature helper migration:
splitSignature(x)/ethers.utils.splitSignature(x)->ethers.Signature.from(x)joinSignature(x)/ethers.utils.joinSignature(x)->ethers.Signature.from(x).serialized
- Transaction helper migration:
parseTransaction(tx)->ethers.Transaction.from(tx)serializeTransaction(tx, sig?)->ethers.Transaction.from({...}).serialized
- AbiCoder migration:
ethers.utils.defaultAbiCoder->ethers.AbiCoder.defaultAbiCoder()- Also ensures
AbiCoder.defaultAbiCoderusage becomes a call.
- Numeric
hexlifymigration:ethers.utils.hexlify(<number-like>)->ethers.toBeHex(...)
defineReadOnlymigration:ethers.utils.defineReadOnly(obj, key, value)->ethers.defineProperties(obj, { [key]: value })
- Adds TODOs for removed utils that require manual migration:
TODO: v6-utils '<name>' removed in v6; migrate manually
6) constants
Flattens ethers.constants.* and handles numeric constants:
- Renamed constants:
AddressZero->ethers.ZeroAddressHashZero->ethers.ZeroHashMaxUint256->ethers.MaxUint256MaxInt256->ethers.MaxInt256MinInt256->ethers.MinInt256WeiPerEther->ethers.WeiPerEtherEtherSymbol->ethers.EtherSymbol
- Numeric namespace constants:
NegativeOne->BigInt("-1")Zero->BigInt("0")One->BigInt("1")Two->BigInt("2")
Also handles constants.* references when constants is bound to ethers.constants.
Manual Follow-Up TODOs
This codemod intentionally inserts TODO comments when migration requires semantic review:
TODO: v6-bigint manual BigNumber chain migrationTODO: v6-provider getSigner() is now async; add awaitTODO: v6-utils '<name>' removed in v6; migrate manually
Search for TODO: v6- after running the codemod and resolve each case manually.
Usage
In codemod workflow
workflow.yaml is configured to run src/index.ts as the transform entrypoint.
Local fixture run
Run the full pipeline on test fixtures:
yarn test:fixtureThis reads src/tests/fixtures/input.ts and writes src/tests/fixtures/output.ts.
Pipeline Options
The top-level transform in src/index.ts accepts:
log(default:true) - enable/disable reporting.reportUnchangedSteps(default:false) - include per-step "no changes" logs.summaryOnly(default:false) - emit only final per-file summary.maxReportHunks(default:3) - maximum changed hunks reported per step.
Project Structure
src/index.ts- orchestrates pipeline execution and reporting.src/transforms/*.ts- individual migration transforms.src/transforms/*.test.ts- transform-specific tests.src/tests/fixtures/*- end-to-end fixture input/output.scripts/run-fixture.ts- fixture runner for quick verification.workflow.yaml- codemod workflow configuration.
Development
yarn install
yarn test
yarn test:coverage
yarn typecheck
yarn buildSafety and Limitations
- The codemod is designed to be idempotent for covered patterns.
- It uses heuristics for provider/contract detection to reduce false positives.
- Ambiguous or behavior-sensitive patterns are intentionally left for manual migration via TODO markers.
- Always run on a dedicated branch and review diffs before merging.
