openzeppelin-contracts icon indicating copy to clipboard operation
openzeppelin-contracts copied to clipboard

Remove isContract due to potential misuse

Open devtooligan opened this issue 2 years ago • 12 comments

In spite of the warnings provided in the comments of the function itself, the name isContract is a misnomer and creates a potential security risk for anyone who doesn't bother to read the notes or someone who is reviewing a 3rd party contract that uses this fn.

There is a misconception that calling this function will return false if the address is an eoa. This can lead to the inadvertant introduction of an exploit and other risks already clearly identified in the comments. But comments inside the function are not enough in this case where the name of the fn is so blatantly misleading.

Propose changing the name of the function to hasCode which is much more descriptive of what the function does. This should be a breaking change and may end up being a wake up call to anyone who has been misusing the fn to date.

devtooligan avatar May 17 '22 17:05 devtooligan

I don't think isContract is a misnomer anymore than hasCode would be. It would be misleading if the function was called isNotEOA, but it's not. hasCode has the same caveats that isContract does, because they're literally synonymous.

kryptoklob avatar May 17 '22 17:05 kryptoklob

Disagree. It's not clear from the name isContract what method is being used to determine if the address is a contract or not. You know it's synonymous, but someone who hasn't looked at the fn has no idea. They just see the fn name and think, oh it's a contrct.

hasCode indicates that the address has code at this moment in time and doesn't come with the implications that isContract does

devtooligan avatar May 17 '22 17:05 devtooligan

There is a misconception that calling this function will return false if the address is an eoa

isContract will always return false for an account that is an EOA. The problem is that that it will also return false for things that are not contracts (i.e. don't have code), but have, will have or have had some of the properties of smart contracts (such as the ability to commit to future action), which in some scenarios defeats the purpose of the check.


That said, I don't quite follow the distinction you're making between 'having code', and 'being a contract'. It seems like everyone uses 'smart contract' to mean 'account with code', so the name change doesn't seem to add much.

nventuro avatar May 17 '22 18:05 nventuro

I guess I should have said, "there is a misconception that if isContract() returns false the address is an eoa."

I guess because there are two types of addresses, those with code and those for eoas. Because you are a seasoned developer, you know that the isContract function is checking if there is code at that address. In fact, you probably wouldn't even use the isContract function in the first place, neither would I. The users of isContract are generally newer users who may not realize that the check for isContract is to check whether or not it has code.

There have been many cases of developers using !isContract thinking it means the address is an eoa and inadvertantly introducing exploits into their code. Changing the name to hasCode removes that implication, and at least forces them to think about it a little more, and maybe even open up the function and read all those helpful comments.

One last question, tbh I feel that removing this function altogether from OZ is the best solution. The reason I submitted this rename issue is because it felt like an acceptable middle ground. Would you be open to a pr that removes all references to isContract altogether?

devtooligan avatar May 17 '22 18:05 devtooligan

I believe an assertIsContract(addr) that reverts if addr has no code is the only safe utility that you can provide. I proposed this to @frangio some time ago, but unfortunately, I've forgotten what the arguments against it were.

PS: I don't understand why hasCode would be different from isContract. That's actually what brought me to this issue. IMO the problem with both is that they return a boolean when only true and unknown are valid answers.

alcuadrado avatar May 17 '22 19:05 alcuadrado

assertIsContract would be safe, but I'm not sure what it would be useful for. isContract is necessary to implement standards like ERC721 and ERC1155.

Nowadays Solidity has addr.code.lengh that we could use directly. When Address.isContract was introduced this feature didn't exist and isContract was used to wrap the necessary assembly.

Note that removal of isContract would be a breaking change, so the best we can do now is to deprecate it and mark it for removal in 5.0. I would be in favor of this.

frangio avatar May 17 '22 19:05 frangio

@frangio I would be a huge supporter of deprecating and removing isContract at next major release as you suggest (and I know many others would as well). Is there anything I can do to help with that?

devtooligan avatar May 17 '22 20:05 devtooligan

The thing is, we need that function in some parts of the repo (ERC721 & ERC1155). We can mark isContract as deprecate and remove it in 5.0, how will be handle the place where it is used ?

  • Will we manually inline the logic? (not a big fan of that)
  • Will we continue providing this function but with a different name? If yes, should we start publishing it with the new name before isContract is removed?

Amxx avatar May 18 '22 07:05 Amxx

@Amxx I would propose manually inlining the logic, but instead of assembly we use address(..).code.size

devtooligan avatar May 18 '22 13:05 devtooligan

@Amxx I would propose manually inlining the logic, but instead of assembly we use address(..).code.size

If this is agreed upon, would love to draft a PR for this. :)

ashwinYardi avatar Aug 04 '22 04:08 ashwinYardi

@ashwinYardi Please open a PR against the next branch (future 5.0).

frangio avatar Aug 11 '22 14:08 frangio

Here we go: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3682

cc @frangio @Amxx

ashwinYardi avatar Sep 06 '22 08:09 ashwinYardi

Fixed in https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3945.

frangio avatar May 31 '23 14:05 frangio