Skip to content
This repository was archived by the owner on Mar 5, 2025. It is now read-only.

Commit 89976a9

Browse files
authored
Ethers Migration guide (#7441)
* update codeowners * migration guide * update * updated code owners * doc update * doc update * docs updates
1 parent ae99434 commit 89976a9

File tree

6 files changed

+355
-468
lines changed

6 files changed

+355
-468
lines changed

.github/CODEOWNERS

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
# https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners
33

44
# Automatically assigns members of the web3.js team to new pending PRs as reviewers
5-
* @avkos @jdevcs @luu-alex @Muhammad-Altabba @krzysu @danforbes
5+
* @jdevcs @AlexeyKrasnoperov
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,345 @@
1+
---
2+
sidebar_label: '🔄 Migration to ethers.js'
3+
title: 'Migration from Web3.js to Ethers.js'
4+
position: 17
5+
---
6+
7+
This guide will help you migrate from web3.js to ethers.js for interacting with the Ethereum blockchain. The guide covers ethers.js v6, providing code examples for both libraries.
8+
9+
### Installation
10+
11+
To begin migrating from Web3.js to ethers.js, first install the ethers.js package:
12+
13+
```
14+
npm install ethers@6
15+
16+
```
17+
18+
### Providers Initialization
19+
20+
When migrating from Web3.js to ethers.js, the first step is to update how you connect to the Ethereum network. Both libraries use providers, but their initialization differs.
21+
22+
```typescript
23+
import { Web3 } from 'web3';
24+
25+
// private RPC endpoint
26+
const web3 = new Web3(providerURL);
27+
28+
const blockNumber = await web3.eth.getBlockNumber();
29+
console.log(blockNumber);
30+
```
31+
32+
To migrate this to ethers.js, you'll need to replace it with JsonRpcProvider. Note that ethers.js separates provider types more explicitly:
33+
34+
```typescript
35+
import { ethers } from 'ethers';
36+
37+
// ethers.js v6
38+
const provider = new ethers.JsonRpcProvider(providerURL);
39+
40+
const blockNumber = await provider.getBlockNumber();
41+
console.log(blockNumber);
42+
```
43+
44+
### Browser-injected Provider
45+
46+
When migrating browser wallet connections, you'll need to update how you handle the injected provider (like MetaMask). Here's your existing Web3.js code:
47+
48+
```typescript
49+
const web3 = new Web3(window.ethereum);
50+
```
51+
52+
In ethers.js v6, you'll need to use the BrowserProvider class instead. This provider is specifically designed for browser environments:
53+
54+
```typescript
55+
// in v6
56+
const provider = new ethers.BrowserProvider(window.ethereum);
57+
```
58+
59+
### Wallets and Accounts - Generate Private Key
60+
61+
If your code generates private keys with Web3.js, here's how to migrate that functionality. Your existing Web3.js code:
62+
63+
```typescript
64+
// this would generate a private key similar to:
65+
// '0x286f65c4191759fc5c7e6083b8c275ac2238cc7abb5915bd8c905ae4404215c9'
66+
// (Be sure to store it encrypted in a safe place)
67+
const privateKey = web3.eth.accounts.create().privateKey;
68+
```
69+
70+
To achieve the same in ethers.js, use the `Wallet.createRandom()` method:
71+
72+
```typescript
73+
// this would generate a private key similar to:
74+
// '0x286f65c4191759fc5c7e6083b8c275ac2238cc7abb5915bd8c905ae4404215c9'
75+
// (Be sure to store it encrypted in a safe place)
76+
const privateKey = ethers.Wallet.createRandom().privateKey;
77+
```
78+
79+
### Wallets and Accounts - Create a wallet
80+
81+
When migrating wallet creation code, you'll need to change how accounts are added to wallets. Your existing Web3.js code using `wallet.add()`:
82+
83+
```typescript
84+
const web3 = new Web3();
85+
const wallet = web3.eth.accounts.wallet.add(
86+
// you can generate a private key using web3.eth.accounts.create().privateKey
87+
privateKey,
88+
);
89+
90+
// outputs: 0x6f7D735dFB514AA1778E8D97EaCE72BfECE71865
91+
console.log(wallet[0].address);
92+
```
93+
94+
In ethers.js, wallet creation uses the Wallet constructor:
95+
96+
```typescript
97+
const wallet = new ethers.Wallet(
98+
// A private key that you might had generated with:
99+
ethers.Wallet.createRandom().privateKey,
100+
// or explicitly given privateKey
101+
);
102+
103+
// outputs: 0x6f7D735dFB514AA1778E8D97EaCE72BfECE71865
104+
console.log(wallet.address);
105+
```
106+
107+
### Get Signer account
108+
109+
When migrating code that gets the current account, you'll need to change from Web3.js's getAccounts():
110+
111+
```typescript
112+
const account = (await web3.eth.getAccounts())[0];
113+
```
114+
115+
To ethers.js's getSigner() method, which returns a signer object instead of just an address:
116+
117+
```typescript
118+
const signer = await provider.getSigner();
119+
```
120+
121+
### Signing
122+
123+
When migrating message signing functionality, you'll need to update from Web3.js's sign methods:
124+
125+
```typescript
126+
// Sign with web3.js, using a private key:
127+
const signature = web3.eth.accounts.sign('Some data', privateKey).signature;
128+
129+
// Sign using an account managed by the connected provider
130+
const signature = await web3.eth.sign(
131+
web3.utils.utf8ToHex('Some data'), // data to be signed (4.x only supports Hex Strings)
132+
'0x6E599DA0bfF7A6598AC1224E4985430Bf16458a4', // the address
133+
);
134+
```
135+
136+
In ethers.js, signing is simplified using the signMessage method:
137+
138+
```typescript
139+
const signer = new ethers.Wallet(privateKey);
140+
const signature = await signer.signMessage('Some data');
141+
```
142+
143+
## Signing and Sending Transactions
144+
145+
### Sending Transactions
146+
147+
When migrating transaction sending code, you'll need to update how transactions are signed and sent. Your existing Web3.js code where transactions are signed using an unlocked or added account:
148+
149+
```typescript
150+
const web3 = new Web3(url);
151+
152+
// Add wallet to be used as a signer
153+
const wallet = web3.eth.accounts.wallet.add(givenPrivateKey);
154+
const account = wallet[0].address;
155+
156+
const tx = await web3.eth.sendTransaction({
157+
from: account,
158+
to: '0x92d3267215Ec56542b985473E73C8417403B15ac',
159+
value: web3.utils.toWei('0.00000000001', 'ether'),
160+
});
161+
console.log(tx);
162+
```
163+
164+
In ethers.js, transactions are sent using a signer instance, which combines the private key and provider:
165+
166+
```typescript
167+
const signer = new ethers.Wallet(privateKey, provider);
168+
169+
const tx = await signer.sendTransaction({
170+
to: '0x92d3267215Ec56542b985473E73C8417403B15ac',
171+
value: ethers.parseUnits('0.001', 'ether'),
172+
});
173+
console.log(tx);
174+
```
175+
176+
### Sending a Signed Transaction
177+
178+
When migrating code that separates transaction signing and broadcasting, you'll need to update from Web3.js's two-step process:
179+
180+
```typescript
181+
const transaction = {
182+
from: senderPublicAddress,
183+
to: receiverPublicAddress,
184+
value: 1,
185+
gas: 21000,
186+
};
187+
188+
const signedTransaction = await web3.eth.accounts.signTransaction(transaction, privateKey);
189+
190+
const tx = await web3.eth.sendSignedTransaction(signedTransaction.rawTransaction);
191+
192+
console.log(tx);
193+
```
194+
195+
In ethers.js, you can broadcast a pre-signed transaction using the provider's broadcastTransaction method:
196+
197+
```typescript
198+
await provider.broadcastTransaction(signedTx);
199+
```
200+
201+
## Contracts
202+
203+
### Contract Deployment
204+
205+
When migrating contract deployment code, you'll need to update from Web3.js's deploy and send pattern:
206+
207+
```typescript
208+
const contract = new web3.eth.Contract(abi);
209+
const deployTx = await contract
210+
.deploy({
211+
data: bytecode,
212+
arguments: ['constructor param'],
213+
})
214+
.send({
215+
from: '0x12598d2Fd88B420ED571beFDA8dD112624B5E730',
216+
gas: '1000000',
217+
});
218+
219+
console.log('contract address', deployTx.options.address);
220+
```
221+
222+
In ethers.js, contract deployment uses the ContractFactory class:
223+
224+
```typescript
225+
const signer = await provider.getSigner();
226+
const factory = new ethers.ContractFactory(abi, bytecode, signer);
227+
const contract = await factory.deploy('constructor param');
228+
console.log('contract address', contract.address);
229+
230+
// wait for contract creation transaction to be mined
231+
await contract.deployTransaction.wait();
232+
```
233+
234+
### Contract Method Calls
235+
236+
When migrating contract method calls, you'll need to update from Web3.js's methods object pattern:
237+
238+
```typescript
239+
const contract = new web3.eth.Contract(ABI, CONTRACT_ADDRESS);
240+
241+
// For read operations
242+
const result = await contract.methods.someFunction().call();
243+
244+
// For write operations
245+
const tx = await contract.methods.someFunction().send();
246+
```
247+
248+
In ethers.js, contract methods are called directly as functions:
249+
250+
```typescript
251+
const contract = new ethers.Contract(CONTRACT_ADDRESS, ABI, provider);
252+
const result = await contract.someFunction();
253+
```
254+
255+
### Contract Events
256+
257+
When migrating event handling code, you'll need to update from Web3.js's events interface:
258+
259+
```typescript
260+
const event = contract.events.SomeEvent({
261+
filter: { val: 100 },
262+
fromBlock: 0,
263+
});
264+
265+
event.on('data', resolve);
266+
event.on('error', reject);
267+
```
268+
269+
In ethers.js, event listening is :
270+
271+
```typescript
272+
contract.on('SomeEvent', (arg1, arg2, event) => {
273+
// event handling
274+
});
275+
```
276+
277+
### Gas Estimation
278+
279+
When migrating gas estimation code, you'll need to update from Web3.js's estimateGas method:
280+
281+
```typescript
282+
const gasAmount = await contract.methods.myMethod(123).estimateGas({
283+
from: transactionSenderAddress,
284+
});
285+
```
286+
287+
In ethers.js, gas estimation is made through a direct method call:
288+
289+
```typescript
290+
const gasEstimate = await contract.myMethod.estimateGas(123);
291+
```
292+
293+
## Utility methods
294+
295+
### Hashing
296+
297+
When migrating code that computes Keccak-256 hashes, you'll need to update from Web3.js's utility methods:
298+
299+
```typescript
300+
// computes the Keccak-256 hash of the input and returns a hexstring
301+
const hash1 = web3.utils.sha3('hello world');
302+
303+
// alternative keccak256 method with broader input support
304+
const hash2 = web3.utils.keccak256('hello world');
305+
```
306+
307+
In ethers.js, hashing requires explicit conversion of strings to bytes:
308+
309+
```typescript
310+
import { keccak256, toUtf8Bytes } from 'ethers';
311+
312+
const message = 'Hello, World!';
313+
const messageBytes = toUtf8Bytes(message);
314+
const hash = keccak256(messageBytes);
315+
```
316+
317+
### Ether Unit Conversion
318+
319+
When migrating code that converts between ether units, you'll need to update from Web3.js's fromWei and toWei methods:
320+
321+
```typescript
322+
// Convert Wei to Ether
323+
const fromWeiToEther = web3.utils.fromWei('1000000000000000000', 'ether');
324+
// outputs: 1
325+
console.log(fromWeiToEther);
326+
327+
// Convert Ether to Wei
328+
const fromEtherToWei = web3.utils.toWei('1.0', 'ether');
329+
// outputs: 1000000000000000000
330+
console.log(fromEtherToWei);
331+
```
332+
333+
In ethers.js, use formatEther and parseEther for common ether conversions:
334+
335+
```typescript
336+
// Convert Wei to Ether
337+
const fromWeiToEther = ethers.formatEther('1000000000000000000');
338+
// outputs: 1.0
339+
console.log(fromWeiToEther);
340+
341+
// Convert Ether to Wei
342+
const fromEtherToWei = ethers.parseEther('1.0');
343+
// outputs: 1000000000000000000n
344+
console.log(fromEtherToWei);
345+
```

0 commit comments

Comments
 (0)