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?
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:
By the
_balances[i]
, I guess you expect to receive the address of wallet. But this actually returns thebalance at address <i>
. Becausei
is the index in this case, so_balances[i]
returns 0 IIRC.https://docs.soliditylang.org/en/v0.8.18/types.html#iterable-mappings