5

referencing the question How to get access to the storage array through the solidity assembler? I have been trying to figure out how to access the mapping (or variable y from the question). The documentation has an example, but of course it has to be overly complicated and access a 2d mapping. However it does say that to get the value of a key (k) of a mapping you hash k . p and load this slot. Does this mean to get the mapping from the similarly asked question you would do:

contract Foo {
  uint internal x; // Storage slot #0
  mapping (uint => address) internal y; // Storage slot #1
  uint [] internal z; // Storage slot #2

  function zElement (uint key) public view returns (uint r) {
    assembly {
      sload(keccak256(add(key, y_slot), 32))
    }
  }
}

EDIT: fixed the link to go to the correctly mentioned question. EDIT2: should compile now i think.

5
  • Would be useful if you posted a code which compiles successfully. Mar 11, 2020 at 13:24
  • the code was taken from the previously asked question. I guess to get it to work u just move the closing bracket of the contract to after the function. I merely had a question related to that answer so I took the answer and edited the sload line for my question.
    – Bobdabear
    Mar 11, 2020 at 13:31
  • So what part are you missing then? Just the uint => address instead of uint => uint part? Mar 11, 2020 at 14:05
  • I guess? i changed it for address but technically nothing was missing. trying to access a mapping value in assembly and I can't figure it out.
    – Bobdabear
    Mar 11, 2020 at 14:14
  • it just doesn't make much sense to me, especially for a key of uint(0) since that would evaluate to sload(keccak256(y_slot, 32)) and the docs say keccak256(y_slot, 32) should be unused for mappings
    – Bobdabear
    Mar 11, 2020 at 14:26

1 Answer 1

7

Solution

function getStorageValue(uint num, uint slot) public view returns (address result) {
    assembly {
        // Store num in memory scratch space (note: lookup "free memory pointer" if you need to allocate space)
        mstore(0, num)
        // Store slot number in scratch space after num
        mstore(32, slot)
        // Create hash from previously stored num and slot
        let hash := keccak256(0, 64)
        // Load mapping value using the just calculated hash
        result := sload(hash)
    } 
}

Explanation

To obtain the address stored behind a uint to address mapping, you have to obtain the storage key and subsequently load the data stored in that position by using sload. To do so you have to hash 64 bytes using keccak256. Those 64 bytes are composed of 32 bytes of the uint you want to use as a key concatenated to 32 bytes of the storage slot. The low-level keccak256 call takes a memory address and a number of bytes as arguments, therefore those values have to be stored cohesive in memory before by using mstore. The storage slot is determined by the position in which the storage variable is declared in comparison to other storage variables, starting from 0.

4
  • omg ur my hero! I've read the opcode info so many times and yet i somehow missed or just didn't care about the fact that keccak256 uses memory location as its first input and not the uint(or bytes32) value. man i feel special.
    – Bobdabear
    Mar 11, 2020 at 16:57
  • @Bobdabear I sure know that feeling! Glad I could help :)
    – sea212
    Mar 11, 2020 at 18:25
  • @sea212 Hi there, I am wondering if you could also help with initializing a mapping with assembly.
    – Maxareo
    Mar 11, 2021 at 6:46
  • @Maxareo Hello, please post a new question about your issue. I cannot promise to help right now, but the community in general is able to and might resolve your issue.
    – sea212
    Mar 17, 2021 at 18:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.