Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ethers v5 target #250

Merged

Conversation

zemse
Copy link
Contributor

@zemse zemse commented Jun 20, 2020

This PR adds a target-ethers-v5 to TypeChain packages and intends to close #205.

Thanks to @krzkaczor and @quezak for v4 target. The v5 target in this PR builds on top of it to update the types changed in ethers v5.

To try it: by cloning repository:

  1. git clone [email protected]:zemse/TypeChain.git or git clone https://github.com/zemse/TypeChain.git
  2. cd TypeChain
  3. yarn (you need yarn installed if you don't)
  4. yarn build (this generates dist dir which is imp)
  5. Link this custom target to your project by placing the appropriate path to the target: typechain --target ../TypeChain/packages/target-ethers-v5/ (Docs)

Just in case if it's too much, I have temporarily published it to npm for testing:

  1. npm install typechain-target-ethers-v5 --save-dev (later you can just replace the package with official one)
  2. typechain --target ethers-v5 (Docs)

Useage

import { Erc20Factory } from '../../interfaces'; // there is an index.ts file which exports all factories

// Deploying
// you only need to pass a signer (abi and bytecode is managed)
const erc20Factory = new Erc20Factory(signer); 
const erc20Instance = await erc20Factory.deploy(); // you will get type suggestions in VSCode.

// Connecting to Existing
const erc20Instance = Erc20Factory.connect(contractAddress, signer);

// For some reason if you need interface of the contract
import { Erc20 } from '../../interfaces/Erc20';
interface Global {
  tokenInstance: Erc20;
}

Please have a look at this if it is fine and let me know of any change I need to make.

@abarmat
Copy link

abarmat commented Jun 22, 2020

I tried this PR on a repo where I have many tests I migrated from ethers-v4 to ethers-v5 using waffle-v3 and worked for me.

.gitignore Outdated
@@ -14,3 +14,4 @@ examples/truffle-v4/types
examples/truffle-v4/migrations
examples/truffle-v5/types
examples/truffle-v5/migrations
.DS_Store
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should go to your global gitignore file. otherwise we will end up with huge list of unrelevant OS files in this file.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That makes sense. Removing this from gitignore file right away.

@krzkaczor
Copy link
Member

This looks great @zemse! Thanks!

I guess more tests would be nice (in a separate directory as we do for other targets).

export function codegenAbstractContractFactory(contract: Contract, abi: any): string {
return `
import { Contract, Signer } from "ethers";
import { Provider } from "ethers/providers";
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@krzkaczor is this ok, or it should be import { Provider } from '@ethersproject/providers'; ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

uhh good call. That's why we need tests + isolated example to catch such problems 😆

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh my bad.. fixing this for now. @krzkaczor I'll have a look at how other tests are written and add the same for v5 here.

@krzkaczor
Copy link
Member

@zemse awesome work! Yeah I would like to hear some feedback from the users. Tests would also be great! We can't publish an official release without them.

interface.encodeFunctionData("transfer", [ to, amount ])

I think it's possible to implement it by using function overloads where first arg type would be string literal "transfer". But yes, it's a little bit more complicated.

@zemse
Copy link
Contributor Author

zemse commented Jun 23, 2020

I think it's possible to implement it by using function overloads where first arg type would be string literal "transfer". But yes, it's a little bit more complicated.

Okay, it's possible then I'll give it a try because it'd be nice to have this too.

@quezak
Copy link
Contributor

quezak commented Jun 23, 2020

I'll take a look tomorrow!

@quezak quezak self-requested a review June 23, 2020 15:45
Copy link
Contributor

@quezak quezak left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've reviewed a diff between this and the v4 target package, code looks good!
Just a nitpick plus a few questions, since I didn't try ethers v5 myself yet.

Comment on lines 3 to 7
export interface GenerateFunctionOptions {
returnResultObject?: boolean
isStaticCall?: boolean
}

Copy link
Contributor

@quezak quezak Jun 24, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd move this interface to the functions.ts file, since it's only used there and doesn't have to be exported. (this file's name types.ts refers to handling code generation for solidity types, not TS types for this package ;) )

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very much thanks for the review. This makes sense and I'll make this change.

Comment on lines 19 to 21
if (allFunctions.match(/\W Overrides(\W|$)/)) contractImports.push('Overrides')
if (allFunctions.match(/\WPayableOverrides(\W|$)/)) contractImports.push('PayableOverrides')
if (allFunctions.match(/\WCallOverrides(\W|$)/)) contractImports.push('CallOverrides')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is the first regex different than the 2nd & 3rd one? (space between \W and the name)

Copy link
Contributor

@quezak quezak Jun 24, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe is it worth extracting a helper fn to increase readability and avoid typos in the regexes? like

function pushImportIfUsed(importName: string, generatedCode: string, importArray: string[]): void {
  if (new RegExp(`\\W${importName}(\\W|$)`).test(generatedCode)) importArray.push(importName);
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was afraid that /\WOverrides(\W|$)/ would match PayableOverrides and CallOverrides too when it shouldn't and should only match Overrides. Is there a better way to do the same? I think would face the same issue having this as a method as the pushImportIfUsed example

Copy link
Contributor

@quezak quezak Jun 24, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've noticed that problem when I wrote those regexes in the ethers-v4 target :) \W means a non-word character, and it's there specifically so \Wxyz doesn't match abcxyz, so it's safe to drop the extra space.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment on lines +105 to +106
? `${constructorArgNamesWithoutOverrides}, overrides || {}`
: 'overrides || {}'
Copy link
Contributor

@quezak quezak Jun 24, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does the ContractFactory require passing empty overrides in v5, since you added the explicit || {} here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When we don't pass any override using typechain's overrides, the overrides is set as undefined. But it looks like ethers v4 was fine with undefined overrides value but in v5 it throws an error. We can make it not pass an undefined override (+1 or 2 lines) or just fall-backing to an empty override as done corrently. Is it good doing like this?

Copy link
Contributor

@quezak quezak Jun 24, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is weird, not passing an optional argument should be handled exactly the same as explicitly passing undefined there. TBH, if passing undefined overrides throws in ethers v5, it's likely a bug there. We can leave the explicit empty overrides for now.

@zemse zemse requested review from krzkaczor and quezak June 28, 2020 12:50
@zemse
Copy link
Contributor Author

zemse commented Jun 28, 2020

I think it's possible to implement it by using function overloads

Thanks for pointers. I've tried to add that.

I've updated the tests for ethers v5. Please have a look and let me know for any changes required.

@krzkaczor krzkaczor changed the base branch from master to fork/ethers-v5-target June 30, 2020 19:23
@krzkaczor krzkaczor merged commit 12141da into dethcrypto:fork/ethers-v5-target Jun 30, 2020
@krzkaczor
Copy link
Member

Thanks for all your hard work! It's moved to internal branch fork/ethers-v5-target. For now.

@krzkaczor
Copy link
Member

It's published as @typechain/ethers-v5, still in beta. Thanks again for your work.

I added an example to my branch and it seems like everything works fine 👍

@zemse
Copy link
Contributor Author

zemse commented Jun 30, 2020

@krzkaczor Thanks for moving it forward! I'm very happy I gave this a shot, this was my first PR in OSS. I have marked the demo published package as deprecated. Let me know if I need to do anything more.

BTW saw the typedAssert while writing tests, It might be common for rest of you guys but for someone like me without a programing background and barely over 1 year exp, honestly I'm was impressed with the cool stuff that I saw in this repo.

One more thing which were exiting for me were the reviews (thanks to everyone for taking time to review the work and guiding me). Sorry if I sound too crazy, but I'm happy that I'm on GitHub, I have access to so many amazing people all around the world. I observed that in preparing PRs on GitHub, we get to learn a lot of best practices since we get to see a lot. So I believe I'll find more opportunities to do.

Hopefully, I'll get to see you all again.

@abarmat
Copy link

abarmat commented Jun 30, 2020

@zemse thank you for your time putting this code together. This PR is super useful for all us using Typechain and Ethers.

@zemse
Copy link
Contributor Author

zemse commented Jul 2, 2020

Hi @HenryNguyen5, I just encountered a problem with staticCall. ethers-io/ethers.js#924

@krzkaczor
Copy link
Member

@zemse wow great work! Especially that it was your first PR to OSS.

I gotta admit that TypeChain is not the easiest project to contribute to, so you should be proud of yourself even more ;)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add target for ethers v5
5 participants