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

BSC网络使用BUSD铸造NFT支付失败问题排查与修复

问题

我正在学习智能合约,目前使用Remix在BSC网络开发NFT铸造功能(该网络与ETH一样采用18位小数)。已实现免费铸造及BNB等原生代币支付的铸造功能,但尝试使用BUSD支付铸造时,虽能通过balanceOf查询到正确余额,执行铸造却触发报错:

Gas estimation errored with the following message (see below). The transaction execution will likely fail. Do you want to force sending?
Returned error: {"jsonrpc":"2.0","error":"execution reverted","id":5075618818565261}

测试合约代码如下:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

contract MyNFT is ERC721URIStorage, Ownable {

    using Counters for Counters.Counter;
    Counters.Counter private _tokenIds;

    ERC20 public _token; // Referencja do ERC20 tokenu
    uint256 public _mintingFee = 1e18; // Opłata za mintowanie NFT
    address tokenAddress = 0xeB3Eb991D39Dac92616da64b7c6D5af5cCFf1627;

    struct NFT {
        string collectionName;
    }

    mapping(uint256 => NFT) private _nfts;

    constructor(uint256 mintingFee) ERC721("MyNFT", "NFT") {
        _token = ERC20(tokenAddress);
        _mintingFee = mintingFee * 1e18;
    }

    function showBUSD() 
        public view 
        returns (uint256)
    {
        return _token.balanceOf(msg.sender);
    }

    function mintNFT(address recipient, string memory tokenURI, string memory _collectionName)
        public onlyOwner 
        returns (uint256)
    {   
        //require(msg.value >= _mintingFee, "Insufficient BNB amount");
        require(_token.balanceOf(msg.sender) >= _mintingFee, "Insufficient balance");
        //require(_token.allowance(msg.sender, address(this)) >= _mintingFee, "Insufficient allowance");
        
        _token.transferFrom(msg.sender, address(this), _mintingFee);
        
        _tokenIds.increment();

        uint256 newItemId = _tokenIds.current();
        _mint(recipient, newItemId);
        _nfts[newItemId].collectionName = _collectionName;
        _setTokenURI(newItemId, tokenURI);

        /*if (msg.value > _mintingFee) {
            payable(msg.sender).transfer(msg.value - _mintingFee);
        }*/

        return newItemId;
    }

    function getCollectionName(uint256 tokenId) 
        public view 
        returns (string memory) 
    {
        return _nfts[tokenId].collectionName;
    }

    function setMintingFee(uint256 newFee) 
        external onlyOwner 
    {
        _mintingFee = newFee * 1e18;
    }
}
解决方案

问题出在以下几个点,对应修复步骤如下:

  • 恢复授权检查逻辑
    ERC20的transferFrom要求用户必须先给合约授权足够的代币额度,即使余额充足,没有授权的话transferFrom会直接触发 revert。取消注释require(_token.allowance(msg.sender, address(this)) >= _mintingFee, "Insufficient allowance");这行代码,确保用户已授权合约转移指定数量的BUSD。

  • 检查ERC20转账返回值
    包括BUSD在内的部分ERC20代币,transferFrom会返回布尔值表示操作成功,但当前代码未检查该返回值。如果转账失败,合约会因返回值不匹配而 revert。将_token.transferFrom(msg.sender, address(this), _mintingFee);替换为:

    bool success = _token.transferFrom(msg.sender, address(this), _mintingFee);
    require(success, "BUSD transfer failed");
    
  • 补充前端授权操作
    在调用mintNFT之前,必须先调用BUSD合约的approve方法,授权你的NFT合约转移_mintingFee数量的BUSD。比如在Remix中,先切换到BUSD合约地址,调用approve,参数填入NFT合约地址和铸造费用(注意保留18位小数),之后再执行mintNFT。

  • 可选:用SafeERC20增强安全性
    导入@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol,使用SafeERC20.safeTransferFrom代替原生transferFrom,它会自动检查返回值并处理异常。修改后核心代码如下:

    import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
    
    contract MyNFT is ERC721URIStorage, Ownable {
        using SafeERC20 for ERC20;
        
        // ...其他代码
        function mintNFT(...) public onlyOwner returns (uint256) {
            // ...余额和授权检查
            _token.safeTransferFrom(msg.sender, address(this), _mintingFee);
            // ...其他铸造逻辑
        }
    }
    

内容的提问来源于stack exchange,提问作者Wraith

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 10:45:11