Solidity重写OpenZeppelin ERC721的safeTransferFrom为payable报错如何解决
问题原因
Solidity 中函数重写要求子类方法的状态可变性必须和父类方法兼容,OpenZeppelin 提供的 ERC721 实现中默认safeTransferFrom方法没有payable修饰符,子类重写时直接添加payable会触发函数签名不匹配的编译错误,报错信息如下:
解决方法
你需要将 ERC721 中所有重载的safeTransferFrom方法都完成重写,统一添加payable修饰符,同时明确指定重写的父合约为ERC721避免歧义。你当前的代码只重写了带bytes参数的版本,还需要补充重写不带bytes参数的重载版本。
修改后的完整合约代码如下:
// SPDX-License-Identifier: MIT pragma solidity ^0.8.2; import "@openzeppelin/contracts@4.3.2/token/ERC721/ERC721.sol"; import "@openzeppelin/contracts@4.3.2/access/Ownable.sol"; import "@openzeppelin/contracts@4.3.2/utils/Counters.sol"; contract MyToken is ERC721, Ownable { using Counters for Counters.Counter; Counters.Counter private _tokenIdCounter; constructor() ERC721("MyToken", "MTK") {} function safeMint(address to) public onlyOwner { _safeMint(to, _tokenIdCounter.current()); _tokenIdCounter.increment(); } // 重写带bytes参数的safeTransferFrom,添加payable function safeTransferFrom( address from, address to, uint256 tokenId, bytes memory _data ) public payable override(ERC721) { require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved"); _safeTransfer(from, to, tokenId, _data); } // 补充重写不带bytes参数的重载版本,同样添加payable function safeTransferFrom( address from, address to, uint256 tokenId ) public payable override(ERC721) { safeTransferFrom(from, to, tokenId, ""); } }
注意事项
- 如果你需要
transferFrom方法也支持附带ETH转账,也可以按照同样的逻辑重写该方法添加payable修饰符。 - 添加
payable修饰符后建议补充对应ETH提取逻辑,避免用户误转ETH到合约后无法取出。
内容的提问来源于stack exchange,提问作者smarinrojas
相关产品推荐
相关产品推荐

