Description
Also reported some time ago in https://forum.openzeppelin.com/t/why-contracts-upgradeable-has-ierc721upgradeable-and-i-whatever-upgradeable/14793
💻 Environment
openzeppelin-contracts == 4.3.2
openzeppelin-contracts-upgradeable == 4.3.2
📝 Details
The package openzeppelin-contracts-upgradeable renames the interfaces when they are exactly the same as non-upgradeable (vanilla) versions. This isn't necessary and brings a lot of issues like this one
🔢 Code to reproduce bug
interface IMyContract is IERC721 {
...
}
contract MyContract is IMyContract, ERC721Upgradeable {
...
}
Then when I compile I get errors like these:
11 | contract PolicyNFT is IERC721,
| ^ (Relevant source part starts here and spans across multiple lines).
Note: Definition in "ERC721Upgradeable":
--> @openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol:184:5:
|
184 | function safeTransferFrom(
| ^ (Relevant source part starts here and spans across multiple lines).
Note: Definition in "IERC721":
--> @openzeppelin/contracts/token/ERC721/IERC721.sol:136:5:
|
136 | function safeTransferFrom(
| ^ (Relevant source part starts here and spans across multiple lines).
TypeError: Derived contract must override function "safeTransferFrom". Two or more base classes define function with same name and parameter types.
I think XXXUpgradeable contracts shouldn't define new interfaces but instead implement the standard ones. Interfaces are the same between upgradeable and non-upgradeable contracts.
If name clashes are an issue when importing files from contracts
and contracts-upgradeable
, those can be easily avoided using explicit imports
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import {ERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";