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

Mantle测试网调用buyPlot函数报错求助:两种实现均出问题

调用Mantle测试网合约buyPlot函数的报错解决

合约详情

合约地址:0xb1DC2063345F6d210AC1f9c9da2aB8131A53b938
ABI:

[
    {
        inputs: [
            {
                internalType: "address",
                name: "_treasury",
                type: "address",
            },
            {
                internalType: "address",
                name: "_token",
                type: "address",
            },
        ],
        stateMutability: "nonpayable",
        type: "constructor",
    },
    {
        anonymous: false,
        inputs: [
            {
                indexed: true,
                internalType: "address",
                name: "previousOwner",
                type: "address",
            },
            {
                indexed: true,
                internalType: "address",
                name: "newOwner",
                type: "address",
            },
        ],
        name: "OwnershipTransferred",
        type: "event",
    },
    {
        anonymous: false,
        inputs: [
            {
                indexed: true,
                internalType: "address",
                name: "buyer",
                type: "address",
            },
            {
                indexed: true,
                internalType: "uint256",
                name: "coord",
                type: "uint256",
            },
            {
                indexed: false,
                internalType: "uint256",
                name: "price",
                type: "uint256",
            },
            {
                indexed: false,
                internalType: "uint256",
                name: "purchaseCount",
                type: "uint256",
            },
        ],
        name: "PlotPurchase",
        type: "event",
    },
    {
        inputs: [
            {
                internalType: "uint256",
                name: "coord",
                type: "uint256",
            },
        ],
        name: "buyPlot",
        outputs: [],
        stateMutability: "payable",
        type: "function",
    },
    {
        inputs: [
            {
                internalType: "uint256",
                name: "startCoord",
                type: "uint256",
            },
            {
                internalType: "uint256",
                name: "endCoord",
                type: "uint256",
            },
        ],
        name: "getAllOwners",
        outputs: [
            {
                internalType: "address[]",
                name: "",
                type: "address[]",
            },
        ],
        stateMutability: "view",
        type: "function",
    },
    {
        inputs: [
            {
                internalType: "uint256",
                name: "startCoord",
                type: "uint256",
            },
            {
                internalType: "uint256",
                name: "endCoord",
                type: "uint256",
            },
        ],
        name: "getAllPurchaseCounts",
        outputs: [
            {
                internalType: "uint256[]",
                name: "",
                type: "uint256[]",
            },
        ],
        stateMutability: "view",
        type: "function",
    },
    {
        inputs: [],
        name: "getOwnerCount",
        outputs: [
            {
                internalType: "uint256",
                name: "",
                type: "uint256",
            },
        ],
        stateMutability: "view",
        type: "function",
    },
    {
        inputs: [],
        name: "mintPerPlot",
        outputs: [
            {
                internalType: "uint256",
                name: "",
                type: "uint256",
            },
        ],
        stateMutability: "view",
        type: "function",
    },
    {
        inputs: [],
        name: "owner",
        outputs: [
            {
                internalType: "address",
                name: "",
                type: "address",
            },
        ],
        stateMutability: "view",
        type: "function",
    },
    {
        inputs: [
            {
                internalType: "address",
                name: "",
                type: "address",
            },
        ],
        name: "plotsOwned",
        outputs: [
            {
                internalType: "uint256",
                name: "",
                type: "uint256",
            },
        ],
        stateMutability: "view",
        type: "function",
    },
    {
        inputs: [
            {
                internalType: "uint256",
                name: "coord",
                type: "uint256",
            },
        ],
        name: "price",
        outputs: [
            {
                internalType: "uint256",
                name: "",
                type: "uint256",
            },
        ],
        stateMutability: "view",
        type: "function",
    },
    {
        inputs: [],
        name: "renounceOwnership",
        outputs: [],
        stateMutability: "nonpayable",
        type: "function",
    },
    {
        inputs: [],
        name: "token",
        outputs: [
            {
                internalType: "contract IERC20",
                name: "",
                type: "address",
            },
        ],
        stateMutability: "view",
        type: "function",
    },
    {
        inputs: [
            {
                internalType: "address",
                name: "newOwner",
                type: "address",
            },
        ],
        name: "transferOwnership",
        outputs: [],
        stateMutability: "nonpayable",
        type: "function",
    },
    {
        inputs: [],
        name: "treasury",
        outputs: [
            {
                internalType: "address",
                name: "",
                type: "address",
            },
        ],
        stateMutability: "view",
        type: "function",
    },
    {
        inputs: [
            {
                internalType: "address",
                name: "tokenAddress",
                type: "address",
            },
            {
                internalType: "uint256",
                name: "amount",
                type: "uint256",
            },
        ],
        name: "withdrawTokens",
        outputs: [],
        stateMutability: "nonpayable",
        type: "function",
    },
    {
        stateMutability: "payable",
        type: "receive",
    },
]

错误实现1及报错

const buyPixel = async (row: number, col: number) => {
  const { gridContract: contract } = getEthers();
  try {
    const row1 = BigInt(123);
    await contract.buyPlot(row1);
    // const column1 = BigInt(c);
    // let r = ethers.parseUnits(row.toString(), 0);
    // let c = ethers.parseUnits(col.toString(), 0);
    // const basePrice = ethers.parseEther("0.1"); // Set the base price in Ether
  } catch (err) {
    console.error("Error buying pixel:", err);
  }
}

报错信息:

Error: missing revert data (action="estimateGas", data=null, reason=null, transaction={ "data": "0x7b1949d2000000000000000000000000000000000000000000000000000000000000007b", "from": "0x64627c96aB9d0a24B8bAA3F53336cbb39Bc6A55a", "to": "0xb1DC2063345F6d210AC1f9c9da2aB8131A53b938" }, invocation=null, revert=null, code=CALL_EXCEPTION, version=6.6.7)

错误实现2及报错

const buyPixel = async (row: number, col: number) => {
  const { gridContract: contract } = getEthers();
  let r = ethers.parseUnits(row.toString(), 0);
  let c = ethers.parseUnits(col.toString(), 0);
  const pxCount = await contract.owner();
  console.log(contract, row, col, r, c, pxCount, "pb");
  try {
    const row1 = BigInt(r);
    const column1 = BigInt(c);
    const basePrice = ethers.parseEther("0.1"); // Set the base price in Ether
    const plotPrice = basePrice * column1 * row1;
    // Send the transaction with the correct amount of Ether (in Wei)
    const overrides = {
      value: ethers.parseUnits(plotPrice + "", 18),
    };
    const result = await contract.buyPlot(row1, column1, overrides);
    console.log(result, "res");
    // Transaction successful, update pixel state
    // setPixels((prevPixels) => {
    //   const updatedPixels = [...prevPixels];
    //   updatedPixels[row][col] = true;
    //   return updatedPixels;
    // });
  } catch (err) {
    console.error("Error buying pixel:", err);
  }
}

报错信息:

Error: no matching fragment (operation="fragment", info={ "args": [ 1, 1, { "value": 100000000000000000000000000000000000 } ], "key": "buyPlot" }, code=UNSUPPORTED_OPERATION, version=6.6.7)

buyPlot合约源码

function buyPlot(uint256 coord) external payable isValidCoord(coord) {
     Plot storage plot = grid[coord];
     uint256 plotPrice = BASE_PRICE << plot.purchaseCount;
     require(msg.value >= plotPrice, "Not enough ETH sent to buy plot");
     if (msg.value > plotPrice) {
         payable(msg.sender).transfer(msg.value - plotPrice);
     }
     address currentOwner = plot.owner;
     // Ensure the sender is not the contract itself
     require(msg.sender != address(this), "Contract cannot buy plots");
     // protocol takes 25% of the purchase price
     // 75% goes to the previous owner
     // if there is no previous owner, 100% goes to the protocol
     // the protocol is the owner of all plots at the start
     if (currentOwner != address(0)) {
         uint256 transferAmount = plotPrice.mul(3) / 4;
         // Ensure the transfer to the current owner is successful
         require(payable(currentOwner).send(transferAmount), "Transfer to current owner failed");
         if (currentOwner != msg.sender) {
             plotsOwned[currentOwner] -= 1;
             plotsOwned[msg.sender] += 1;
             plot.owner = msg.sender;
         }
     } else {
         plot.owner = msg.sender;
         plotsOwned[msg.sender] += 1;
     }
     // Transfer the purchase price to the contract owner
     if (address(this).balance > 0) {
         require(payable(treasury).send(address(this).balance), "Transfer to treasury failed");
     }
     plot.purchaseCount += 1;
     // mint tokens for the buyer
     token.safeTransfer(msg.sender, mintPerPlot);
     emit PlotPurchase(msg.sender, coord, plotPrice, plot.purchaseCount);
}

问题分析与解决方案

错误实现2的核心问题

从ABI和合约源码可知,buyPlot仅接受单个coord参数,但实现2传入了row1、column1两个参数+overrides,参数数量不匹配,直接触发no matching fragment错误。

错误实现1的核心问题

实现1仅传入了coord参数,但未附带ETH金额,合约要求msg.value >= plotPrice,交易因金额不足被revert;missing revert data通常是节点未返回具体revert原因,但本质是交易不符合合约规则。

正确实现步骤

  1. 将row和col转换为单个coord值:合约用单个uint256类型的coord标识地块位置,需根据合约isValidCoord的规则编码(例如coord = row * 网格宽度 + col,需替换为实际网格宽度)。
  2. 获取地块实时价格:调用合约price(coord)函数获取当前价格,不要自行计算——价格会随purchaseCount动态翻倍(plotPrice = BASE_PRICE << plot.purchaseCount)。
  3. 附带正确ETH金额调用:通过overrides传入value参数,值为获取到的plotPrice。

正确代码示例

const buyPixel = async (row: number, col: number) => {
  const { gridContract: contract } = getEthers();
  try {
    // 1. 根据网格规则计算coord,此处假设网格宽度为100,需替换为实际值
    const gridWidth = 100;
    const coord = BigInt(row * gridWidth + col);
    
    // 2. 获取该地块的当前价格
    const plotPrice = await contract.price(coord);
    
    // 3. 调用buyPlot并附带对应ETH
    const overrides = {
      value: plotPrice
    };
    const tx = await contract.buyPlot(coord, overrides);
    await tx.wait();
    console.log("交易成功:", tx.hash);
  } catch (err) {
    console.error("Error buying pixel:", err);
  }
}

额外注意事项

  • 确认isValidCoord修饰器的规则,确保计算出的coord合法,否则会触发revert。
  • 若仍出现missing revert data,可尝试更换Mantle测试网节点,或手动指定gasLimit关闭自动gas估算,但优先保证交易参数正确。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 02:02:01