开发者问题收集

将结构数组传递给 Solidity 合约的构造函数

2022-03-21
4632

我正在使用 solidity 构建 NFT 智能合约,并且在部署合约时尝试将结构数组传递到构造函数中。但是我收到以下错误。

TypeError: Cannot read property 'length' of undefined

联系代码是:

contract MetropolisWorldGenesis {

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

    struct PropertyAttributes {
        uint id;
        string name;
        string description;
        string image;
        Properties properties;
    }

    struct Properties {
        string tower;
        string disctrict;
        string neighborhood;
        string primary_type;
        string sub_type_1;
        string sub_type_2;
        string structure;
        string feature_1;
        string feature_2;
        string feature_3;
        string feature_4;
        string feature_5;
        string rarity;
        // string internal_id;
    }

    //store a list of all the NFT's available to mint. 
    //this is built on when the constructor is called. 
    PropertyAttributes[] defaultProperties;

    //store which has been minted. 
    mapping(uint => bool) public MintedNfts;

    //map the nft tokenid to the atributes 
    mapping(uint256 => PropertyAttributes) public nftAttributes;

    constructor(PropertyAttributes[] memory props) { 
        console.log("OK I am making the contract, just this once mind");

        for (uint i = 0; i < props.length; i += 1){
             defaultProperties.push(props[i]);

             PropertyAttributes memory p = defaultProperties[i];
             console.log("Done initializing %s w/ HP %s, img %s", p.name, p.description, p.image);
        
    } 
}

我使用以下命令调用它:

const main = async () => {

    // make up the data from t he json 
    const nftList = require('./nft_list_finalv2.json')
    
    let props = []

    for(var i=0; i < nftList['nfts'].length;i+=1){
        
        x = nftList['nfts'][i]['metadata']
        props.push(x)
    }
    
    console.log(props.length)

    // deply the contract will the data made above. 
    const propertyContractFactory = await hre.ethers.getContractFactory('MetropolisWorldGenesis');
    const propertyContract = await propertyContractFactory.deploy(
        props
    );
    await propertyContract.deployed();
    console.log("Contract deployed to:", propertyContract.address);
  };
  
  const runMain = async () => {
    try {
      await main();
      process.exit(0);
    } catch (error) {
      console.log(error);
      process.exit(1);
    }
  };
  
  runMain();

Json 文件是结构如下的项目数组。

{ 'nfts':[
     {
            "id": 1,
            "metadata": {
                "id": 1,
                "name": "tester",
                "description": "Rtestt",
                "image": "",
                "properties": {
                    "tower": "Tower 1",
                    "district": "Hir",
                    "neighborhood": "Fres",
                    "primary_type": "Whause",
                    "sub_type_1": "Aboned",
                    "sub_type_2": "Fors",
                    "structure": "Dark brick",
                    "feature_1": "Df",
                    "feature_2": "Gins",
                    "feature_3": "Castes",
                    "feature_4": "Cloors",
                    "feature_5": "e walls",
                    "rarity": "",
                    "internal_id": "Tower 1_1"
                }
            },
            "price": 10,
            "ipfs": "",
            "img_name": "WqmYMT02j.png",
            "map_ref": "Z"
        },
....
]}

我在 javascript 端获得了正确的数据数组,但当我将其传递到合约中时似乎出现了一些错误。 我在这里遗漏了什么?

3个回答

实际上,您可以将结构作为参数传递给 solidity 中的构造函数。我自己在一份合约中这样做:

struct UserConfig {
        address user;
        address userToken;
        uint userSlippage; 
    }

    struct FixedConfig { 
        address inbox;
        address ops;
        address PYY;
        address emitter;
        uint maxGas;
    }

FixedConfig fxConfig;
VariableConfig varConfig;


constructor(
        FixedConfig memory fxConfig_,
        VariableConfig memory varConfig_
    ) {
        fxConfig = fxConfig_;
        varConfig = varConfig_;
    }

您会将其作为数组传递到 ethers.js 上。

我遇到的问题以及我最初写这篇文章的原因在于,当您将数组传递给 ethers 上的 deploy() 时,它会更改合约中结构上变量的顺序。所以我想弄清楚为什么会发生这种情况。

dNyrM
2022-05-15

您也可以将结构传递给外部和公共可见性功能。
如果您的功能是这样的:

625436381

,那么您可以这样传递这些:

983292445

只有结构具有钥匙值对的对象,您也可以对此进行嵌套结构。
我希望它会有所帮助!

adityanithariya
2023-02-17

上次我检查时,没有办法将 struct 传递给 构造函数 请参阅此处的 2018 年答案 )。它说:

...you cannot pass struct to a constructor as it will be receiving its input outside from the blockchain. Only the private and internal functions can expect structs as input parameters.

解决方案是使用“原始”数据类型作为输入。对于您的特定情况,可以修改构造函数以接受一个 NFT 对象,例如:

constructor (
  int NFTsId,
  int MetaId,
  string MetaName,
  string MetaDescription,
  string MetaImage,
  string PropertiesTower,
  string PropertiesDistrict,
  ...,
  uint MetaPrice,
  string MetaIPFS,
  ...
) {
  // Assign values
}

或者,您可以编写构造函数以接收数组中的多个输入并根据它们的索引位置重新定位它们(​​第一个 MetaId 与第一个 MetaName 一起...):

constructor (
  int[] memory NFTsIds,
  int[] memory MetaIds,
  string[] memory MetaNames,
  string[] memory MetaDescriptions,
  string[] memory MetaImages,
  string[] memory PropertiesTowers,
  string[] memory PropertiesDistricts,
  ...,
  uint[] memory MetaPrices,
  string[] memory MetaIPFSs,
  ...
) {  
  for (uint256 i=0; i < NFTsId.length; i ++){
    NFTsId = NFTsIds[i];
    ...
    // Assign values
  }
}

需要指出的是, for 循环将消耗大量的 gas,具体取决于发送给构造函数的 NFT 对象的数量。

Nico Serrano
2022-03-21