3

I'm looking at the code of some smart contracts and I've seen somewhere where the code is something like:

if (msg.sender == storage[0x00] & 0xffffffffffffffffffffffffffffffffffffffff)

From my limited understanding, 0xfffff is always true, isn't it? What is the reason of having it there? In other places I see 0xff instead of the whole f deal, is there any difference?

Thanks

Hiperfly
  • 459
  • 4
  • 11

1 Answers1

4

I'm looking at the code of some smart contracts and I've seen somewhere where the code is something like...

I've only ever seen this type of snippet in a decompiled contract, rather than a "human coded" one.

msg.sender == storage[0x00]

This part is checking that the address stored in slot 0 of the stack matches the sender of the current transaction. I'd guess that what it's really checking is (probably) msg.sender == owner, where the contract owner was set in the contract's constructor, and set as the first private variable in the contract (i.e. slot 0). (Again, I think what you're looking at is probably a decompiled version.)

From my limited understanding, 0xfffff is always true

In this case, 0xffffffffffffffffffffffffffffffffffffffff is a 20-byte long bitmask.

...& 0xffffffffffffffffffffffffffffffffffffffff

This is a bitwise AND operation (single &), not a logical AND (double &&).

Noting that addresses are also 20 bytes (160 bits) long, this mask allows the address to be type-checked. This effectively coerces whatever you're &ing into a 160-bit integer (which it should be anyway), as the EVM explicitly requires addresses to be 160 bits.


Edit - A bit more detail:

  1. Order or operations

Considering the two operations, bitwise & has a higher precedence than the equality operator ==, meaning we mask the value and then check it matches the address in slot0. (See the docs.)

  1. Why we actually need the mask

The EVM word size is 32 bytes (256 bits). But an address is only 20 bytes long, meaning we have to pad the remaining 12 bytes. The other thing to note is that byte types are all left-aligned, meaning the address is stored as the following:

0xDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF000000000000000000000000
^                20 bytes                ^^        12 bytes      ^
+----------------------------------------++----------------------+

We want to remove the padding. To do this, we use the mask (also of type bytes):

0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000000

&ing them together gives us:

0xDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF
Richard Horrocks
  • 37,835
  • 13
  • 87
  • 144
  • Oh I see thanks a lot, very well explained. You are correct, this is from a decompiled contract. I should assume then that as an extra security step, the contract is not actually storing the owner address itself, but some sort of 'artificial' hash that when applied the bitmask to, results in the owner address? So, the bitmask is applied before the == operator?Thanks again! – Hiperfly Apr 14 '21 at 19:00
  • 1
    Hi again. I've added some more details to address your comment (I had to remind myself why we actually use the mask - I was a bit vague before!) – Richard Horrocks Apr 15 '21 at 15:49
  • 1
    This is greatly explained, thanks a lot for the clarification. Have a nice day! – Hiperfly Apr 16 '21 at 09:23
  • No problem - you too! – Richard Horrocks Apr 16 '21 at 10:23