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

DynamicSvgNft合约问题:getHighSVG与getLowSVG返回值颠倒

DynamicSvgNft合约SVG URI返回值混淆问题修复

问题现象

合约中getHighSVG()返回s_lowImageURI的值,getLowSVG()返回s_highImageURI的值,导致测试结果不符合预期——高SVG的获取函数返回低SVG的URI,反之亦然。

相关代码

合约代码(DynamicSvgNft.sol)

// DynamicSvgNft.sol

contract DynamicSvgNft is ERC721, Ownable {
 uint256 private s_tokenCounter;
 string private s_lowImageURI;
 string private s_highImageURI;
 AggregatorV3Interface internal immutable i_priceFeed;

 mapping (uint256 => int256) private s_tokenToHighValue;

 event CreatedNft(uint256 indexed tokenId, int256 highValue);

 constructor(address priceFeedAddress, string memory lowSvg, string memory highSvg) ERC721("Dynamic SVG NFT", "DSN") {
     s_tokenCounter = 0;
     i_priceFeed = AggregatorV3Interface(priceFeedAddress);
     s_lowImageURI = svgToImageUri(lowSvg);
     s_highImageURI = svgToImageUri(highSvg);

 }

 // functionalities
 
 function mintNft(int256 highValue) public {
     _safeMint(msg.sender, s_tokenCounter);
     s_tokenToHighValue[s_tokenCounter] = highValue;
      s_tokenCounter = s_tokenCounter + 1;
     emit CreatedNft(s_tokenCounter, highValue);
 }

 function svgToImageUri(string memory svg) public pure returns (string memory) {
     // convert the svgs to image uris and store them in variables for later use
     string memory baseURL = "data:image/svg+xml;base64,";
     string memory svgBase64Encoded = Base64.encode(bytes(string(abi.encodePacked(svg))));
     return string(abi.encodePacked(baseURL, svgBase64Encoded));
 }


 function _baseURI() internal pure override returns (string memory) {
     return "data:application/json;base64,";
 }

 function tokenURI(uint256 tokenId) public view override returns (string memory) {
     if(!_exists(tokenId)) {
         revert ERC721Metadata__URI_QueryFor_NonExistentToken();
     } 

     (, int256 price, , , ) = i_priceFeed.latestRoundData();

     string memory imageURI;
     if (price >= s_tokenToHighValue[tokenId]) {
           imageURI = s_highImageURI;
     } else {
          imageURI = s_lowImageURI;
     }
     return
         string(
         abi.encodePacked(
             _baseURI(),
             Base64.encode(
                 bytes(
                     abi.encodePacked(
                         '{"name":"',
                         name(),
                         '", "description":"An NFT that changes based on the chainlink feed",',
                         '"attributes": [{"trait_type": "coolness", "value": 100}], "image":"',
                         imageURI,
                         '"}'
                     )
                 )
             )
         )
         );
 }
 function getLowSVG()  public view returns (string memory) {
     return s_lowImageURI;
 }
   function getHighSVG()  public view returns (string memory) {
     return s_highImageURI;
 }
 function getTokenCounter() public view returns (uint256 ) {
     return s_tokenCounter;
 }
 function getPriceFeed() public view returns (AggregatorV3Interface) {
     return i_priceFeed;
 }
}

测试代码(DynamicSvgNft.test.js)

// DynamicSvgNft.test.js

const highSVGImageUri = "data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMjAwIDIwMCIgd2lkdGg9IjQwMCIgIGhlaWdodD0iNDAwIiB4bWxucz0";
const lowSVGImageUri = "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/...";

describe("Constructor", () => {
    it("sets the initial values correctly", async () => {
        const highSVG = await dynamicSvgNft.getHighSVG(); // Returns lowSVGImageUri instead of the highSVGImageUri
        const lowSVG = await dynamicSvgNft.getLowSVG();   // Returns the highSVGImageUri instead of the lowSVGImageUri
        // ... (assertions)
        console.log(`highSVG is => ${highSVG}`)
        assert.equal(highSVG, highSVGImageUri)
        console.log(`lowSVG is => ${lowSVG}`)
        assert.equal(lowSVG, lowSVGImageUri)
        assert.equal(tokenCounter.toString(), "0")
        assert.equal(priceFeed, MockV3Aggregator.address)
    });
});

// ... (other test code)

部署脚本(DynamicSvgNft.deploy.js)

// DynamicSvgNft.deploy.js

const { network } = require("hardhat");
const { developmentChains, networkConfig } = require("../helper-hardhat-config");
const { verify } = require("../utils/verify");
const fs = require("fs")

module.exports = async ({getNamedAccounts, deployments}) => {
    const {deploy, log} = deployments
    const {deployer} = await  getNamedAccounts()

    const chainId = network.config.chainId
    let ethUsdPriceFeedAddress

    if(developmentChains.includes(network.name)) {
        const EthUsdAggregator = await deployments.get("MockV3Aggregator")
        ethUsdPriceFeedAddress  = EthUsdAggregator.address
    } else {
        ethUsdPriceFeedAddress = networkConfig[chainId].ethUsdPriceFeed
    }

    log("#####################################");

    // read the nft images
    const lowSVG =  fs.readFileSync("images/dynamicNft/frown.svg", {encoding: "utf8"})
    const highSVG =  fs.readFileSync("images/dynamicNft/happy.svg", {encoding: "utf8"})
    args = [ethUsdPriceFeedAddress, highSVG, lowSVG]

    const dynamicSvgNft = await deploy("DynamicSvgNft", {
        from: deployer,
        args:args,
        log: true,
        waitConfirmations: network.config.blockConfirmations || 1
    })

    if(!developmentChains.includes(network.name) && process.env.ETHERSCAN_API_KEY) {
        log("verifying.....")
        await verify(dynamicSvgNft.address, args)
        log("verified!")

        log("#########################################")
    }

}
module.exports.tags = ["all", "dynamicsvg", "main"]

问题根源

合约构造函数定义的参数顺序为:(address priceFeedAddress, string memory lowSvg, string memory highSvg),但部署脚本中传递的参数顺序是[ethUsdPriceFeedAddress, highSVG, lowSVG]——将highSVG传给了lowSvg参数,lowSVG传给了highSvg参数。

这导致构造函数中:

  • s_lowImageURI = svgToImageUri(lowSvg)实际存储的是highSVG转换后的URI
  • s_highImageURI = svgToImageUri(highSvg)实际存储的是lowSVG转换后的URI

最终调用getHighSVG()返回的是lowSVG的URI,getLowSVG()返回的是highSVG的URI,完全颠倒。

修复方案

修改部署脚本中的参数顺序,使其与合约构造函数的参数顺序匹配:

将部署脚本中的:

args = [ethUsdPriceFeedAddress, highSVG, lowSVG]

改为:

args = [ethUsdPriceFeedAddress, lowSVG, highSVG]

验证步骤

  1. 清理之前的部署记录(Hardhat环境下运行npx hardhat clean)
  2. 重新部署合约:npx hardhat deploy --tags dynamicsvg
  3. 运行测试:npx hardhat test
  4. 检查测试输出,确认getHighSVG()返回highSVGImageUri,getLowSVG()返回lowSVGImageUri

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 03:07:04