3

In solidity, immutable fields are stored on bytecode and not at the storage slot. So, if I want to query how can I do it?

eg:

pragma solidity >=0.7.0 <0.9.0;

contract MyContract {
  uint private immutable myValue;

  constructor (uint someValue) {
    myValue = someValue;
  }
}

So, in this case, how can I read myValue ??

In the Bytecodes view in etherscan I can see PUSH32 0x000000000000000000000000000000000000000000000ff2056c038062100000 which is the hex of the someValue that I passed to the constructor.

But is there a better/simpler way to have a getter for the private immutable fields?

2
  • Are you asking from a dev PoV or from the PoV of a user of another contract? If it's your code, simply add a getter, or better simply set public instead of private to let the compiler create a getter for you. Otherwise, the only way to get that value is inspecting the code: the value assigned to an "immutable variable" at construction time is actually used to inject that fixed value inside the final runtime bytecode of the smart contract, everywhere it's used (i.e., in a getter function). Please note in your example you don't use that value, so no injection is made to the runtime code. Commented Jul 20, 2023 at 14:39
  • I was asking the POV that there is already deployed contract with a private immutable filed and I need to read that data and show the calculation on the dapp side. It seems manual inspection is the only way. Thanks Commented Jul 20, 2023 at 15:14

1 Answer 1

5
+50

Summary

You can examine the bytecode of the contract to find the value, the same applies for constants. This way, you could find any value.

You would have to examine the contract bytecode to figure these values out.

Explained

A private immutable is stored in the same location as a constant variable - in the contract bytecode, not in storage.

Take the following contract:

// SPDX-License-Identifier: MIT
pragma solidity 0.8.18;

contract MyContract {
  uint256 immutable private i_myNum;

  constructor() {
    i_myNum = 7;
  }
}

After compilation, you will get the following opcodes:

PUSH1 0xA0 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH1 0xF JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x7 PUSH1 0x80 DUP2 DUP2 MSTORE POP POP PUSH1 0x80 MLOAD PUSH1 0x3F PUSH1 0x2E PUSH1 0x0 CODECOPY PUSH1 0x0 POP POP PUSH1 0x3F PUSH1 0x0 RETURN INVALID PUSH1 0x80 PUSH1 0x40 MSTORE PUSH1 0x0 DUP1 REVERT INVALID LOG2 PUSH5 0x6970667358 0x22 SLT KECCAK256 SAR 0xF8 0xCC SWAP3 EXP 0xD5 CALL SIGNEXTEND PUSH24 0x87D051DBA8AE93B2D48F9CB166A944EC16E3EDE76D5BD64 PUSH20 0x6F6C634300081200330000000000000000000000

In solidity, we can split this up into it's 3 sections (construction, runtime, metadata) by finding the 3 INVALID opcodes.

Contract Construction:

PUSH1 0xA0 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH1 0xF JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x7 PUSH1 0x80 DUP2 DUP2 MSTORE POP POP PUSH1 0x80 MLOAD PUSH1 0x3F PUSH1 0x2E PUSH1 0x0 CODECOPY PUSH1 0x0 POP POP PUSH1 0x3F PUSH1 0x0 RETURN INVALID 

Runtime:

PUSH1 0x80 PUSH1 0x40 MSTORE PUSH1 0x0 DUP1 REVERT INVALID 

Metadata:

LOG2 PUSH5 0x6970667358 0x22 SLT KECCAK256 SAR 0xF8 0xCC SWAP3 EXP 0xD5 CALL SIGNEXTEND PUSH24 0x87D051DBA8AE93B2D48F9CB166A944EC16E3EDE76D5BD64 PUSH20 0x6F6C634300081200330000000000000000000000

We know that immutable variables are set in the contract construction, so we can start looking at just that code, and breaking it out into what each set of opcodes is "doing".

The first few opcodes are just setting up a free memory pointer.

PUSH1 0xA0 PUSH1 0x40 MSTORE 

Then, we do some checks to see if msg.value > 0

CALLVALUE DUP1 ISZERO PUSH1 0xF JUMPI PUSH1 0x0 DUP1 REVERT

Then we see these opcodes:

JUMPDEST POP PUSH1 0x7 

And after breaking down the rest of the opcodes, we find out they are loading 0x7 (aka, 7) into memory to assign to our private variable.

2
  • 1
    So basically we conclude, that we need to dig into the opcodes to check the constant/immutable variables. Like there is no tool for this right? Commented Jul 19, 2023 at 5:57
  • Pretty much. Someone could make such a tool pretty easily either disassembling the opcodes as described above, or using a verified contract as a starting point and then reading the constructor args. Commented Jul 20, 2023 at 23:38

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.