1

I made some experiments with assembly, unfortunately, there is not much documentation and most of them cover the same topics (maths operations, extcodesize, etc.). Here I'm trying to read my state variables, when I have only one variable it works, but it seems that it is not the case anymore with several variables.

the pointer seems to point to the wrong place, so I tested different methods

pragma solidity ^0.8.0;

contract Assembly {
  
    bool private var1 = true;
    bool private var2 = false;
    uint8 private var3 = 8;


    function getThirdVariable() public view returns(uint8 res, uint8 res2, uint8 res3, uint8 res4) {
        assembly {
            res := var3.slot
            res2 := var3.offset
            res3 := sload(var3.slot)
            res4 := sload(var3.offset)
        }
    }
}

Here are the returns of my function:

uint8: res 0
uint8: res2 2
uint8: res3 1
uint8: res4 0

any help would be greatly appreciated

1 Answer 1

1

That's because state variables are packed in storage slots when possible.

Your variables have the following size in storage :

boolean : 1 byte
uint8   : 1 byte 

Given that a storage slot is 32 bytes, all three of them can fit in the first slot (0).

You can check it with this function :

function getSlots() public view returns (uint256, uint256, uint256) {
  uint256 slotVar1;
  uint256 slotVar2;
  uint256 slotVar3;

  assembly {
    slotVar1 := var1.slot
    slotVar2 := var2.slot
    slotVar3 := var3.slot
  }

  return (slotVar1, slotVar2, slotVar3); // 0, 0, 0
}

Now, because they are packed in the same slot they cannot have the same offset :

function getOffsets() public view returns (uint256, uint256, uint256) {
  uint256 offsetVar1;
  uint256 offsetVar2;
  uint256 offsetVar3;

  assembly {
    offsetVar1 := var1.offset
    offsetVar2 := var2.offset
    offsetVar3 := var3.offset
  }

  return (offsetVar1, offsetVar2, offsetVar3); // 0, 1, 2
}

Which is reflected by the value slot 0 itself :

0x0000000000000000000000000000000000000000000000000000000000080001

Where byte 0 : 0x01 is var 1 (bolean true), byte 1 : 0x00 is var 2 (boolean false) and byte 2 : 0x08 is var 3 (uint8 8).

To get the third variable, you want 1 byte from storage slot var3.slot starting at offset var3.offset :

function getThirdVariable() public view returns(uint8) {
  uint8 value;

  assembly {
    let tmp := sload(var3.slot)           // get the value at var3.slot
    tmp := shr(mul(var3.offset, 8), tmp)  // shift that value by var3.offset * 8 bits to the right
    value := tmp                          // store the result for return
  }

  return value; // 8
}
2
  • thank you very much ! do you have any doc your recommend for assembly?
    – Adam Boudj
    Mar 18, 2022 at 21:37
  • The official one (docs.soliditylang.org/en/v0.8.13/…) , it could be improved but it's good enough, then just try some stuff and play with the EVM :/
    – hroussille
    Mar 18, 2022 at 21:53

Your Answer

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

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