I am new in this smart contract area. So what I am learning right now is that when we are deploying a new contract then the data from the old contract will not be automatically moved to the new contract and we need to create a migration function by ourselves to migrate the data from old contract to the new contract. I tried to create the migration function by taking some reference from another post. But when I try to compile the contract, I find this error

TypeError: Member "length" not found or not visible after argument-dependent lookup in mapping(address => mapping(uint256 => uint256)).

This error happens inside this function

function transferData(address payable newContractAddress) public {
    // Reference the new contract
    NFTMinter newContract = NFTMinter(newContractAddress);

    // Transfer each balance
    // ERROR HAPPEN HERE
    for (uint256 i = 0; i < _balances.length; i++) {
      newContract.setBalance(_balances[i], _balances[_balances[i]]);
    }

    // Transfer each tokenIds array
    // ERROR HAPPEN HERE
    for (uint256 i = 0; i < _tokenIds.length; i++) {
      for (uint256 j = 0; j < _tokenIds[i].length; i++) {
        newContract.addTokenId(_tokenIds[i], _tokenIds[i][j]);
      }
    }

    // Transfer each token price
    // ERROR HAPPEN HERE
    for (uint256 i = 0; i < tokenPrice.length; i++) {
      newContract.setTokenPrice(tokenPrice[i], tokenPrice[tokenPrice[i]]);
    }
}

This is how my whole contract looks like

contract NFTMinter is ERC1155 {
  constructor() ERC1155("https://raw.githubusercontent.com/noopmood/TutorialNFTInGo/main/metadata/{id}.json") payable {}
  
  // Define the mapping of addresses to balances
  mapping(address => mapping(uint256 => uint256)) public _balances;

  // Define the mapping of address to tokenIds owned
  mapping(address => uint256[]) public _tokenIds;

  // Define the mapping of tokenId to price
  mapping(uint256 => uint256) public tokenPrice;

  struct Token {
    uint256 tokenId;
    uint256 balance;
  }

  // Mints new tokens and sets the price for each token.
  function mintAddress(uint256 tokenId, uint256 amount, address addr, uint256 price) public{
    _mint(addr, tokenId, amount, "");
    // Update the balance of the recipient
    _balances[addr][tokenId] += amount;
     // Add the tokenId to the address
    _tokenIds[addr].push(tokenId);
    // Set the price of the token
    tokenPrice[tokenId] = price;
  }

  // Get all tokenIds from its owner address
  function getTokenIdsByAddress(address addr) public view returns (uint[] memory) {
    return _tokenIds[addr];
  }

  // Get the tokenIds along with its corresponding balances/amount
  function getAllTokenByAddress(address holder) public view returns (Token[] memory) {
    Token[] memory result = new Token[](_tokenIds[holder].length);
    for (uint i = 0; i < _tokenIds[holder].length; i++) {
      result[i].tokenId = _tokenIds[holder][i];
      result[i].balance = _balances[holder][_tokenIds[holder][i]];
    }
    return result;
  }

  function transferData(address payable newContractAddress) public {
    // Reference the new contract
    NFTMinter newContract = NFTMinter(newContractAddress);

    // Transfer each balance
    for (uint256 i = 0; i < _balances.length; i++) {
      newContract.setBalance(_balances[i], _balances[_balances[i]]);
    }

    // Transfer each tokenIds array
    for (uint256 i = 0; i < _tokenIds.length; i++) {
      for (uint256 j = 0; j < _tokenIds[i].length; i++) {
        newContract.addTokenId(_tokenIds[i], _tokenIds[i][j]);
      }
    }

    // Transfer each token price
    for (uint256 i = 0; i < tokenPrice.length; i++) {
      newContract.setTokenPrice(tokenPrice[i], tokenPrice[tokenPrice[i]]);
    }
  }

  function setBalance(address addr, uint256 balance) public {
    _balances[addr] = balance;
  }

  function addTokenId(address addr, uint256 tokenId) public {
    _tokenIds[addr].push(tokenId);
  }

  function setTokenPrice(uint256 tokenId, uint256 price) public {
    tokenPrice[tokenId] = price;
  }
}

Can anyone help me on figuring out this issue so I am able to compile the contract and able to migrate the data from my old to new contract?

1

There are 1 answers

0
PySoL On

As the error state, there's no length attribute for the map type. Based on the solidity document, there's no way to iterate through the map items.

You need to maintain an array of the address separately in order to loop through it.

Besides that, this block of code is wrong:

// Transfer each balance
    for (uint256 i = 0; i < _balances.length; i++) {
      newContract.setBalance(_balances[i], _balances[_balances[i]]);
    }

By the _balances[i], I guess you expect to receive the address of wallet. But this actually returns the balance at address <i>. Because i is the index in this case, so _balances[i] returns 0 IIRC.

https://docs.soliditylang.org/en/v0.8.18/types.html#iterable-mappings