Search code examples
ethereumsolidity

How to interact with mapping of mappings for structs in solidity?


I have created struct with nested mapping. Consider the following piece of code written inside the contract in solidity:

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.4;

contract TestContract {
  struct Item {
    uint itemId;
    uint itemValue;
  }

  struct OverlayingItemStruct {
    mapping(uint => Item) items;
    uint overlayingId;
    uint itemsCount;
  }
  mapping(uint => OverlayingItemStruct) public overlayingItems;
  uint public overlayCount;

  function addOverlayingItemsStruct(uint _value) external {
    overlayCount ++;
    mapping(uint => Item) memory items;
    items[1] = Item(1, _value);
    overlayingItems[overlayCount] = OverlayingItemStruct(items, 1, 1);
  }

  function addItem(uint _value, uint _overlayId) external {
    OverlayingItemStruct storage overlay = overlayingItems[_overlayId];
    overlay.itemsCount ++;

    overlay.items[overlay.itemsCount] = Item(overlay.itemsCount, _value);
  }
}

When compiling the above code, I am getting the error:

TypeError: Uninitialized mapping. Mappings cannot be created dynamically, you have to assign them from a state variable.
  --> TestC.sol:21:5:
   |
21 |     mapping(uint => Item) memory items;
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Not sure, how to handle this error. Secondly, needed to confirm if the method to add new values in the nested mapping dictionary is correct?


Solution

  • A mapping cannot be declare inside a function and in memory state. This type has only storage state. Said this, to pass a mapping into a struct, you can set the key of nested mapping and pass relative struct inside it. I tried to adjust your smart contract like this:

    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.4;
    
    contract TestContract {
    
      struct Item {
        uint itemId;
        uint itemValue;
      }
    
      struct OverlayingItemStruct {
        mapping(uint => Item) items;
        uint overlayingId;
        uint itemsCount;
      }
    
      mapping(uint => OverlayingItemStruct) public overlayingItems;
      
      uint public overlayCount;
    
      function addOverlayingItemsStruct(uint _value) external {
        overlayCount ++;
        // NOTE: I declared a new Item struct
        Item memory item = Item(1, _value);
        // NOTE: I set into items mapping key value 1, Item struct created in row above this 
        overlayingItems[overlayCount].items[1] = item;
      }
    
      function addItem(uint _value, uint _overlayId) external {
        OverlayingItemStruct storage overlay = overlayingItems[_overlayId];
        overlay.itemsCount ++;
        overlay.items[overlay.itemsCount] = Item(overlay.itemsCount, _value);
      }
    }