You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 17:27:01