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

getPrice函数在用户无免费额度时触发RPC错误,求修复方案

问题修复方案

错误根源

触发execution reverted的核心原因是整数乘法溢出:

  • 若使用Solidity 0.8.0+版本,编译器默认开启整数运算溢出检查,当price.mul(_quantity)的结果超出uint256的最大值(2^256-1)时,会直接触发revert。
  • 若使用0.8.0以下版本,虽无默认溢出检查,但乘积超出范围会导致数值绕回,后续逻辑可能引发异常(你当前场景更偏向0.8+版本的溢出检查触发)。

你的getPrice函数逻辑本身没问题,但运算过程的溢出导致了执行失败。


具体修复步骤

1. Solidity合约修复

方案A:使用SafeMath库(兼容所有Solidity版本)

引入OpenZeppelin的SafeMath,用安全运算避免溢出:

import "@openzeppelin/contracts/utils/math/SafeMath.sol";

contract YourNFT {
    using SafeMath for uint256;
    uint256 public constant maxFree = 1;
    uint256 public constant price = 2200000000000000; // 0.0022 ETH(以wei为单位)

    // 记录用户已铸造数量
    mapping(address => uint256) public mintedCounts;

    function getPrice(address _sender, uint256 _quantity) public view returns (uint256) {
        uint256 _userFreeAmount = maxFree.sub(mintedCounts[_sender]);
        if (_userFreeAmount <= 0) {
            return price.mul(_quantity);
        } else if (_quantity.sub(_userFreeAmount) <= 0) {
            return 0;
        } else {
            return price.mul(_quantity.sub(_userFreeAmount));
        }
    }

    // 补充publicMint函数(确保mintedCounts正确更新)
    function publicMint(uint256 _quantity) external payable {
        // 此处需校验msg.value与getPrice返回值一致,以及其他铸造逻辑
        mintedCounts[msg.sender] += _quantity;
        // ... 其他铸造逻辑(如NFT mint、转账等)
    }
}

方案B:Solidity 0.8+版本简化写法

0.8+版本自带溢出检查,可直接用原生运算符;若确定单次铸造数量不会过大,也可手动跳过检查提升效率:

contract YourNFT {
    uint256 public constant maxFree = 1;
    uint256 public constant price = 0.0022 ether; // 直接用ether后缀更直观

    mapping(address => uint256) public mintedCounts;

    function getPrice(address _sender, uint256 _quantity) public view returns (uint256) {
        uint256 _userFreeAmount = maxFree - mintedCounts[_sender];
        if (_userFreeAmount <= 0) {
            // 若限制单次最大铸造数量(如100),可放心用unchecked
            unchecked {
                return price * _quantity;
            }
        } else if (_quantity <= _userFreeAmount) {
            return 0;
        } else {
            unchecked {
                return price * (_quantity - _userFreeAmount);
            }
        }
    }
}

2. 前端辅助防御

在调用合约前限制单次铸造数量,从源头避免溢出场景:

const mint = async () => {
    let myProvider = web3.currentProvider;
    let networkCheck = myProvider.networkVersion == null ? myProvider.chainId : myProvider.networkVersion;
    if (networkCheck == CHAINID) {
        if (contract && account) {
            const quantity = parseInt($('.supply').text());
            // 新增:限制单次最大铸造数量,比如100个
            if (quantity > 100) {
                alert("单次最多铸造100个NFT");
                return;
            }
            try {
                const price = await contract.methods.getPrice(account, quantity).call();
                await contract.methods.publicMint(quantity).send({ from: account, value: price });
                $.statusSection.init("minting success.");
            } catch (error) {
                alert(error.name);
                alert(error.message);
            }
        }
    } else {
        await switchNetwork();
        location.reload();
    }
}

额外校验点

  1. 确认price的单位为wei:0.0022 ETH等于2200000000000000 wei,若直接写0.0022未加ether后缀,会导致数值错误。
  2. 确保mintedCounts在publicMint函数中正确更新,否则_userFreeAmount的计算会出错。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 17:53:30