Solidity合约Evolution报需标记为abstract报错解决方案
错误产生原因
Solidity 语法规定:如果合约继承了接口或者抽象合约,必须实现所有父合约/接口中标记为virtual、且没有提供默认实现的函数;如果多个父合约存在同名函数重写冲突,也必须在子合约中显式重写该函数指明调用逻辑。如果不满足以上要求,合约就属于未完全实现的抽象合约,无法直接部署,编译器就会抛出Contract "Evolution" should be marked as abstract的错误。
你当前触发该错误的具体原因有几个:
- 存在拼写错误:你写的
ERC721Enumarable名称错误,正确的可枚举ERC721实现合约名为ERC721Enumerable,且你当前代码只导入了IERC721Enumerable接口,没有导入对应的实现合约。 - 继承ERC721系列合约时没有补全必要逻辑:ERC721、ERC721Enumerable、ERC721Royalty这几个合约中存在多个需要子合约重写的虚函数(包括接口校验、转账钩子、销毁钩子等),同时ERC721的构造函数要求传入NFT集合名称、符号两个初始化参数,你当前合约完全没有实现这些逻辑。
- 你当前仅继承
IERC721Receiver的代码本身也存在隐患:该接口要求实现onERC721Received回调函数,否则调用safeTransferFrom向本合约转NFT时会直接回滚。
修复方案
按以下步骤修改代码即可正常编译部署:
- 修正导入和合约名拼写:补充导入ERC721Enumerable、ERC721Royalty的实现合约,把继承列表里拼写错误的
ERC721Enumarable改成ERC721Enumerable。
需要补充的导入:import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol"; - 补全构造函数,调用所有父合约的初始化逻辑,传入ERC721要求的集合名称、符号参数:
constructor() ERC721("Evolution NFT", "EVOL") { // 可补充自己的初始化逻辑,比如设置版税、初始化计数器等 } - 显式重写所有父合约存在冲突、要求实现的虚函数,示例代码如下:
// 重写多父合约冲突的接口校验函数 function supportsInterface(bytes4 interfaceId) public view override(ERC721, ERC721Enumerable, ERC721Royalty) returns (bool) { return super.supportsInterface(interfaceId); } // 重写转账前钩子,保证ERC721Enumerable的枚举逻辑正常运行 function _beforeTokenTransfer( address from, address to, uint256 firstTokenId, uint256 batchSize ) internal override(ERC721, ERC721Enumerable) { super._beforeTokenTransfer(from, to, firstTokenId, batchSize); } // 重写销毁函数,保证ERC721Royalty的版税数据能正常清理 function _burn(uint256 tokenId) internal override(ERC721, ERC721Royalty) { super._burn(tokenId); } // 实现IERC721Receiver要求的接收回调,保证合约能正常接收转入的NFT function onERC721Received(address, address, uint256, bytes calldata) external pure returns (bytes4) { return IERC721Receiver.onERC721Received.selector; } - 如果你需要额外继承Ownable、ReentrancyGuard、Counters等工具合约,直接在继承列表中添加即可,这类合约没有需要子合约强制实现的虚函数,不会触发抽象合约报错。
注意:所有重写函数的override括号里的父合约列表,要和你实际继承的合约对应,如果你没有继承ERC721Royalty,就把它从override列表里删掉即可。
内容的提问来源于stack exchange,提问作者Salih Baran
相关产品推荐
相关产品推荐

