I tried to create a function which could return me 2 different booleans after I call it two times in a row. I tried my best to use different random methods like storing block.timestamp in an uint, or using the keccak256 on different values and compare them, but i can't manage to get it to return once a true and once a false on a consistent manner. I have also have to say that the function is view only, so making a storage variable and increment it doesn't work, I have to work only with memory variables. If anyone have an idea on how can I get that done would be great.

  • 1
    This post is straight up asking for the solution for an ongoing CTF (quillctf.super.site/challenges/quillctf-challenges/true-xor) , please don't answer it.
    – Foxxxey
    Jan 17, 2023 at 22:52
  • @Foxxxey why would I ever need a function like this? Or is this just a fun task to hone solidity skills?
    – Sky
    Jan 17, 2023 at 22:55
  • 1
    @Sky 2nd option, yeah. It's just a challenge
    – Foxxxey
    Jan 17, 2023 at 22:56
  • 1
    You should consider things that change between calls. Time doesn't change, neither msg.sender.
    – Ismael
    Jan 19, 2023 at 14:37

1 Answer 1


So, i know this is a very old topic but i was reviewing my raised flags and found that a mod suggested that i answer this question after the CTF was over (which is definitely the case by now). There's a few approaches to this one, the one i'm gonna present here is the one i went with. My code was

contract BoolGiver is IBoolGiver {
  uint a = 1;
  function giveBool() external view returns(bool) {
    uint gasBefore = gasleft();
    uint b = a;
    uint gasAfter = gasleft();
    return(gasBefore - gasAfter >= 2100);

Let's break it down and explain why it works.

The code simply records the gas it costs to access a storage variable (its value and what is done with is arent important here, only how much gas it costs) and returns true if it's 2100 or more, and false otherwise. This is gonna return true the first time the function is called in a transaction, and false for any subsequent calls.

So, why does that work? After the Berlin hard fork, the gas cost for the SLOAD opcode (reading a storage slot) became dynamic. If the slot is cold (i.e. It has never been accessed (read from or wrote to) during the transaction, SLOAD costs 2100 gas, if the slot is warm (= has been accessed before during the transaction), it costs 100 gas. So, leveraging that mechanic of the EVM to get a view function that returns 2 different bools when it's called 2 times in a row is trivial.

The official solution just uses the total amount of gas consumed by the transaction, and is arguably less good as it fully depends on the amount of gas sent with the transaction in the first place to work.

Relevant links https://www.evm.codes/#54?fork=shanghai / https://eips.ethereum.org/EIPS/eip-2929 / https://hackmd.io/@fvictorio/gas-costs-after-berlin

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.