Migration of OpenZeppelin Contracts tests to Ethers.js

Has there ever been a discussion to migrate the current stack of hardhat web3.js to something else?

1 Like

Are you referring to the OpenZeppelin Contracts repository?

Mostly the tests,

My personal experience with ethers.js has always been easier

But yes, the main contracts repository

Yes we have definitely talked about this and we would love to be using Ethers.js. Unfortunately there is a lot of code that needs to be migrated and it's a huge effort that we don't yet know how best to tackle.

I'm attempting the migration myself and so far it has been yielding good outcomes,

you can see the files here

1 Like

That is very interesting that you're doing that. Are you finding anything particularly challenging?

We noticed you're using Ethers v5, but it seems nowadays we would want to use Ethers v6. Any thoughts?

Note that many are moving to Foundry/Forge.

So you might wanna consider porting from web3.js to that, rather than to ethers.js.

1 Like

It has been very smooth, way more than I expected,

And so far I didn't need any of the custom helpers, so that is less code to maintain

About ethersv5 and v6 the v6 was facing some conflict issues so I started with v5 just to see how it was but I am willing to change that

What are the advantages in using foundry?

Yes, a bit part of the motivation for migrating to Ethers.js would be to finally deprecate our test helpers that we sadly haven't been able to maintain properly, and instead use Hardhat Chai Matchers and Network Helpers.

We would definitely want to go with Ethers v6 at this point.


Regarding Foundry, we use it for its fuzzing in a few specific places, but migrating the entire test suite from Hardhat to Foundry is an entirely different level of effort than migrating from Ethers.js to Web3.js, and we have no plans to do it.

1 Like

Another main reason we are interested in this migration (and Ethers v6 in particular) is to move to native JavaScript BigInts. A line like:

expect(await this.mock.nonces(voterBySigAddress)).to.be.bignumber.equal(nonce.addn(1));

would become:

expect(await this.mock.nonces(voterBySigAddress)).to.be.equal(nonce + 1n);

Coincidentally, I have just finished migrating what I had done so far to ethers v6, let know if you have any comments

Its faster then hardhat :slight_smile:
But for more importantly, your contracts are written in solidity, it is only logical to also write your unit tests in the same language. This prevents any issues with incorrect/invalid conversions. So you don't have to learn a 2nd language (js) and i have a major dislike of nodejs, which for me is reason alone :stuck_out_tongue:

I don't buy this argument. Solidity is not a good general purpose language.

@RenanSouza2 That looks good!

I don't think it makes sense for you to push this to completion at the moment, mainly because we are currently focused on 5.0 and will not be able to review it, and we will want this to be merged very swiftly once we start the migration, because the tests could diverge.

Because of that difficulty it will probably be better for us to do the migration gradually, as opposed to in one big PR that migrates all tests.

What would be very useful for us is if you could report your experience so far:

  • Did you run into anything particularly challenging?
  • Is it feasible to run Ethers (v6) tests along with Truffle tests, so that we do the migration gradually like I described?
  • Anything else you think could be worth sharing.

True, solidity is a pretty limited/basic language. However you write all your business logic in solidity in your smart contract. So to accurately test it you need to use the same language which has/uses the same idiosyncrasies.
When I started out with solidity I had a lot of issues getting my hardhat unit tests to work correctly with ethers and getting the numbers/calculations correctly.
For me the switch to foundry writing unit testing became a lot easier and faster. Same with actually running/compiling them.

The incentive is not to have the tests in Solidity, but to have them in the same language as the contracts, which reduces friction during development and maintenance.

The other incentive is execution time of course, which as a result of inter-process communication in the current framework (between offchain and EVM), is much longer.

Equivalently, the new framework allows for the execution of many more test cases during the same time-frame.

Thanks for letting me know,

so, some discoveries:

1 - some files are very straightforward to migrate, like AccessControl

2 - some are very hard like Governor because of the way the GovernorHelper is implemented, this one will take some more planning

3 - With the exception of makeInterfaceId, all the other helpers in the @openzeppelin/test-helpers could be replaced so far by native ethers.js features, so It may be the case of integrating what remais from that repository and here

5 - web3 and ethersjs tests can run in paralel, you can see here: https://github.com/RenanSouza2/openzeppelin-contracts/tree/ethersjs/access-control/main

6 - there are a bunch of dependencies thay maybe will be able to be uninstalled:
@nomiclabs/hardhat-truffle5
@nomiclabs/hardhat-web3
eth-sig-util
ethereumjs-util
ethereumjs-wallet
keccak256
web3

If I remember something else I'll post here

3 Likes

Another thing,

The ethersjs v6 documentation is still being worked on so many things are incomplete

Hardhat chai matcher does not use AddressLike type implemented in v6 that allows to use signers or contracts as address arguments. This one is importnt because until the matchers are updated they use is not consistent with the rest of the code

1 Like