Skip to content

Instantly share code, notes, and snippets.

@mqklin
Created May 30, 2023 10:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mqklin/2999a7b222e9af4f2bf67c7df3b2869e to your computer and use it in GitHub Desktop.
Save mqklin/2999a7b222e9af4f2bf67c7df3b2869e to your computer and use it in GitHub Desktop.
# Migration of the SanR dApp (https://sanr.app) from ethers v5 to ethers v6
## Introduction
SanR, a decentralized application (dApp) built on the Ethereum blockchain, recently underwent a migration from ethers v5 to ethers v6. This migration involved several changes in the codebase to ensure compatibility and leverage the enhanced features and improvements introduced in the latest version of ethers.js. In this article, we will explore the key modifications made during the migration process and their implications for the SanR dApp.
## Transition from BigNumber to BigInt
One significant change in ethers v6 is the replacement of the BigNumber class with [BigInt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt). BigInt provides more precise handling of large numbers and aligns with the JavaScript standard. It is important to note that JavaScript requires explicit conversion from BigInt to perform operations with regular numbers (Number).
```jsx
- if (ethers.BigNumber.isBigNumber(value[key])) {
+ if (typeof value[key] === 'bigint') {
// token.createdAt is a BigNum now
- const daysPassed = Math.ceil((now - token.createdAt) / 60 / 60 / 24);
+ const daysPassed = Math.ceil((now - Number(token.createdAt)) / 60 / 60 / 24);
```
## Restructuring of Methods
Many methods have been moved from the `utils` and `providers` namespaces directly to the root object in ethers v6. This restructuring simplifies the access and usage of these methods.
```jsx
- const wallet = new Wallet(privateKey, new ethers.providers.JsonRpcProvider('https://sanrchain-node.santiment.net/'));
+ const wallet = new Wallet(privateKey, new ethers.JsonRpcProvider('https://sanrchain-node.santiment.net/'));
- await adminWallet.sendTransaction({to: wallet.address, value: ethers.utils.parseEther('1.0')});
+ await adminWallet.sendTransaction({to: wallet.address, value: ethers.parseEther('1.0')});
- const salt = ethers.utils.keccak256(ethers.utils.toUtf8Bytes('default'));
+ const salt = ethers.keccak256(ethers.toUtf8Bytes('default'));
- filter += `, "issuerAddress":["${ethers.utils.getAddress(issuerAddress)}"]`;
+ filter += `, "issuerAddress":["${ethers.getAddress(issuerAddress)}"]`;
```
## **Introduction of Transaction Batching**
In ethers v6, transaction batching allows developers to bundle multiple transactions into a single batch, reducing network costs and improving efficiency. By default, transaction batching is enabled in ethers v6, allowing users to take advantage of this feature. However, in the case of SanR, which utilizes its own blockchain called the SanR Network that currently does not support transaction batching, the feature can be explicitly disabled using the new **`batchMaxCount`** parameter.
```jsx
- const L2Provider = new ethers.providers.JsonRpcProvider(L2.url);
+ const L2Provider = new ethers.JsonRpcProvider(L2.url, null, {batchMaxCount: 1});
```
Please note that transaction batching was already available in ethers v5, and it remains a valuable feature in ethers v6, with default activation unless explicitly disabled when not needed.
## Method Invocation Changes
Several changes were made regarding method invocations in contract interactions:
- The populateTransaction method and the method name have switched positions.
- In ethers v6, there is no longer a need to specify the function signature when a method can accept multiple arguments.
```jsx
- await L2CompetitionsContract.populateTransaction.createGame(
+ await L2CompetitionsContract.createGame.populateTransaction(
- await L2CompetitionsContract.populateTransaction['makeStake(uint256)'](ethers.utils.parseUnits('500')),
+ await L2CompetitionsContract.makeStake.populateTransaction(ethers.parseUnits('500')),
- await L2SignalsContract.populateTransaction['closeSignals(uint256[],bytes32[],bool[],uint256[],uint256[])'](
+ await L2SignalsContract.closeSignals.populateTransaction(
```
## Renaming of Contract Address Field
In ethers v6, the `address` field of a contract has been renamed to `target`. This change brings greater clarity and consistency to the naming conventions within ethers.js.
```jsx
- <SubheaderValue>{L2CompetitionsContract.address}</SubheaderValue>
+ <SubheaderValue>{L2CompetitionsContract.target}</SubheaderValue>
```
## Renaming of Event Field
The `event` field in events has been renamed to `fragment.name` in ethers v6. This modification provides a more descriptive and precise representation of event fragments.
```jsx
- <JustifyCenter>{el.event === 'Staked' ? 'stake' : el.event === 'Rewarded' ? 'reward' : 'unstake'}</JustifyCenter>
+ <JustifyCenter>{el.fragment.name === 'Staked' ? 'stake' : el.fragment.name === 'Rewarded' ? 'reward' : 'unstake'}</JustifyCenter>
```
## Contract Proxy Transition
In ethers v6, the Contract object has transitioned from being an `object` to an element of `Proxy`. This change affected the `React.propTypes` validation for contract objects, requiring them to be replaced with any. However, it is worth noting that the ethers.js main developer, [@ricmoo.eth](https://twitter.com/ricmoo), has announced plans to rectify this [issue](https://github.com/ethers-io/ethers.js/issues/4084), allowing developers to use object validation once again.
```jsx
- L1SANContract: object.isRequired,
+ L1SANContract: any.isRequired,
```
## Copying Response from Contract Calls
The transformation of contracts into Proxy also impacted how responses from contract method calls are shallow copied. Failure to perform this shallow copy could result in missing object properties in the new object. Developers need to ensure proper handling of copying contract call responses to maintain data integrity.
```jsx
- const _token = {...await Contract.followings(tokenId)};
- const token = {..._token};
+ const token = (await Contract.followings(tokenId)).toObject();
```
## Method Changes in defaultAbiCoder
In ethers v6, the defaultAbiCoder is now a method instead of a property. Developers should update their code accordingly to utilize this method.
```jsx
- const infoHash = ethers.utils.keccak256(ethers.utils.defaultAbiCoder.encode(
+ const infoHash = ethers.keccak256(ethers.AbiCoder.defaultAbiCoder().encode(
```
## Renaming of formatBytes32String
The function formatBytes32String has been renamed to encodeBytes32String in ethers v6. This change aligns with the naming conventions and offers a more descriptive name for the functionality.
```jsx
- const currentPrice = await L2PricesContract.currentPrice(ethers.utils.formatBytes32String('BTC/USD'))).price;
+ const currentPrice = await L2PricesContract.currentPrice(ethers.encodeBytes32String('BTC/USD'))).price;
```
## Provider Renaming and GSN Adjustment
The Web3Provider has been renamed to BrowserProvider in ethers.js v6. Additionally, if you are using OpenGSN version 2, modifications to the request method are necessary for GSN provider integration.
```
```jsx
+ const gsnProvider = await RelayProvider.newProvider({
+ provider: window.ethereum,
+ config,
+ }).init();
+ gsnProvider.request = function(payload) {
+ return new Promise((resolve, reject) => {
+ gsnProvider.send(payload, function(error, result) {
+ if (error) {
+ reject(error);
+ }
+ else {
+ resolve(result?.result);
+ }
+ });
+ });
+ };
const Provider = GSN_CONTRACTS.includes(params.to.toLowerCase())
- ? new ethers.providers.Web3Provider(
- await RelayProvider.newProvider({
- provider: window.ethereum,
- config,
- }).init(),
- )
+ ? new BrowserProvider(gsnProvider)
: WindowEthereumProvider
;
```
## Asynchronous getSigner Method
In ethers v6, the getSigner method has been updated to be asynchronous, allowing for more efficient handling of signer-related operations.
```jsx
- const tx = await Provider.getSigner().sendTransaction(params);
+ const tx = await (await Provider.getSigner()).sendTransaction(params);
- const signedMessage = await Provider.getSigner().signMessage(originalMessage);
+ const signedMessage = await (await Provider.getSigner()).signMessage(originalMessage);
```
## Renaming of transactionHash Field
The transactionHash field of the transaction receipt has been renamed to hash in ethers v6. This change provides a more consistent naming convention across the library.
```jsx
- const tx = await Provider.getTransaction(receipt.transactionHash);
+ const tx = await Provider.getTransaction(receipt.hash);
```
## Removal of confirmations Field
The confirmations field has been removed from Transaction objects in ethers v6. To determine the number of confirmations for a mined transaction, developers should access the confirmations property from the TransactionReceipt object.
```jsx
- const isMined = await Provider.getTransaction(sentTx.hash)).confirmations > 0;
+ const isMined = Boolean(await Provider.getTransactionReceipt(sentTx.hash))
```
## Conclusion
The migration of the SanR dApp from ethers.js v5 to ethers.js v6 involved several notable changes in code structure and functionality. These modifications were necessary to leverage the advancements and improvements offered by ethers.js v6.
We invite you to visit the [SanR platform](https://sanr.app) and explore the exciting features and opportunities it offers. Join us on our platform and experience the power of decentralized applications in action!
Please note that this article is a summary of the changes introduced during the migration process. For more detailed information and guidance, we recommend referring to the ethers.js [documentation](https://docs.ethers.org/v6/migrating/) and [release notes](https://github.com/ethers-io/ethers.js/releases).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment