Polygon网络NFT铸造异常:疑与MATIC-USD价格转换相关
交易哈希
- 失败交易哈希:
0x0f7b19fffae4f2bb88322012ab1e8c04fb5006211df499804da3843ac3ebc1fb - 成功交易哈希:
0x330aba13791482042ce95c1f642fbcebc68ff306dd24c159d82c18c4ebdf3552
问题描述
部署在Polygon网络的NFT铸造合约仅第一笔交易成功,后续所有铸造尝试均失败。本地开发环境及测试网中合约mint函数运行完全正常,期间未修改MATIC兑USD的价格获取逻辑,但怀疑问题出在此模块。
相关代码
PriceConverter 合约代码
/** * @dev Get the latest price from a Chainlink Price Feed and convert it to a fixed-point integer. * @param _priceFeed The Chainlink Price Feed interface. * @return The latest price in fixed-point integer format (with 10 additional decimal places). */ function getPrice(AggregatorV3Interface _priceFeed) internal view returns (uint256) { unchecked { try _priceFeed.latestRoundData() returns ( uint80 roundId, int256 answer, uint256, uint256 , uint80 answeredInRound ){ if(answer <= 0) revert AnswerIsNotGreaterThanZero(); if(roundId != answeredInRound) revert InconsistentRoundId(); return uint256(answer); } catch { revert CantFetchLatestRoundData(); } } } /** * @dev Convert an amount in MATIC to its equivalent value in USD using a Chainlink Price Feed. * @param _maticAmount The amount in MATIC to convert. * @param _priceFeed The Chainlink Price Feed interface. * @return The equivalent value in USD (with 10 additional decimal places). */ function getConversionRate(uint256 _maticAmount, AggregatorV3Interface _priceFeed) internal view returns (uint256) { unchecked { uint256 maticPrice = getPrice(_priceFeed); uint256 decimals = _priceFeed.decimals(); uint256 maticAmountInUsd = (maticPrice * _maticAmount) / 10 ** decimals; // The actual MATIC/USD conversion rate, after adjusting the extra 0s. return maticAmountInUsd; } } /** * @dev Convert an amount in USD to its equivalent value in MATIC using a Chainlink Price Feed. * @param _usdAmount The amount in USD to convert. * @param _priceFeed The Chainlink Price Feed interface. * @return The equivalent value in MATIC (with 10 additional decimal places). */ function getMaticValueFromUsd(uint256 _usdAmount, AggregatorV3Interface _priceFeed) internal view returns (uint256) { unchecked { uint256 maticPrice = getPrice(_priceFeed); uint256 decimals = _priceFeed.decimals(); uint256 maticValue = (_usdAmount * 10 ** decimals) / maticPrice; // The actual USD/MATIC conversion rate, after adjusting the extra 0s. return maticValue; } }
Mint 函数代码
function mint() external payable { uint16 localNftQuantityMinted = nftQuantityMinted; uint256 nftPriceInMatic = nftPriceUsd.getMaticValueFromUsd(priceFeed); // CHECKS if(msg.sender != owner()){ unchecked { if(nftCountPerAddress[msg.sender] >= maxNftsAllowedPerUser) revert Only10NFTsPerAddress(); } } unchecked { if(localNftQuantityMinted >= maxNftsAllowed) revert AllNFTsMinted(); } unchecked { if(msg.value < nftPriceInMatic) revert InsufficientFunds({required: nftPriceUsd}); } unchecked { if(msg.value > nftPriceInMatic) revert UserIsOverpaying({required: nftPriceUsd}); } // EFFECTS // Mark the ID as minted _mintedIds[localNftQuantityMinted] = true ; unchecked { ++nftCountPerAddress[msg.sender]; } ++nftQuantityMinted; // INTERACTIONS // Transfer MATIC to this contract from the sender account bytes memory data = bytes("0x"); _mint(msg.sender, localNftQuantityMinted, 1, data); emit NFTMinted(msg.sender, localNftQuantityMinted); // Set royalty for the token minted _setTokenRoyalty(localNftQuantityMinted, safe, 1000); }
排查方向
参数传递错误(核心嫌疑)
mint函数中调用getMaticValueFromUsd时参数顺序完全错误:函数定义要求第一个参数是USD金额(_usdAmount),第二个是Chainlink价格喂料接口(_priceFeed),但代码中写成了nftPriceUsd.getMaticValueFromUsd(priceFeed),把喂料地址当成USD金额传入,导致计算出的nftPriceInMatic完全不符合预期,触发InsufficientFunds或UserIsOverpayingrevert。正确调用应为getMaticValueFromUsd(nftPriceUsd, priceFeed)。Chainlink价格喂料的roundId检查过严
getPrice中要求roundId == answeredInRound,主网环境下Chainlink喂料更新时可能出现answeredInRound大于roundId的情况,这个检查会导致无法获取价格,触发InconsistentRoundIdrevert。建议放宽条件为answeredInRound >= roundId,确保获取的是有效价格。精度匹配问题
确认Polygon上MATIC/USD价格喂料的小数位数(通常为8位),检查nftPriceUsd的小数位数是否与喂料匹配。若nftPriceUsd是按1e18精度定义的USD价格,计算时需调整精度避免结果异常。交易失败原因确认
通过Polygonscan查看失败交易的具体revert信息,明确是价格获取失败还是金额校验失败,缩小排查范围。
内容的提问来源于stack exchange,提问作者alexsc_

