# MagicNumber

## Description

To solve this level, you only need to provide the Ethernaut with a `Solver`, a contract that responds to `whatIsTheMeaningOfLife()` with the right number.

Easy right? Well... there's a catch.

The solver's code needs to be really tiny. Really reaaaaaallly tiny. Like freakin' really really itty-bitty tiny: 10 opcodes at most.

**Hint:** Perhaps its time to leave the comfort of the Solidity compiler momentarily, and build this one by hand O\_o. That's right: Raw EVM bytecode.

Good luck!

## Background Knowledge

{% embed url="<https://medium.com/coinmonks/ethernaut-lvl-19-magicnumber-walkthrough-how-to-deploy-contracts-using-raw-assembly-opcodes-c50edb0f71a2>" %}
0xSage MagicNumber Walkthrough
{% endembed %}

## Code Audit

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract MagicNum {

  address public solver;

  constructor() {}

  function setSolver(address _solver) public {
    solver = _solver;
  }

  /*
    ____________/\\\_______/\\\\\\\\\_____        
     __________/\\\\\_____/\\\///////\\\___       
      ________/\\\/\\\____\///______\//\\\__      
       ______/\\\/\/\\\______________/\\\/___     
        ____/\\\/__\/\\\___________/\\\//_____    
         __/\\\\\\\\\\\\\\\\_____/\\\//________   
          _\///////////\\\//____/\\\/___________  
           ___________\/\\\_____/\\\\\\\\\\\\\\\_ 
            ___________\///_____\///////////////__
  */
}
```

The ASCII art is 42, which is the answer to `whatIsTheMeaningOfLife()`. Our objective is to build a set of opcodes (<= 10 bytes) that answers 42 when `whatIsTheMeaningOfLife()` is called.

## Solution

We have to prepare 3 things to tackle this challenge:

1. Runtime code
2. Creation code
3. Factory contract

### Step 1: runtime code

The naive approach is writing a contract containing only one function that returns 42. For example:

```solidity
contract Hack {
    function whatIsTheMeaningOfLife() external pure returns (uint) {
        return 42;
    }
}
```

This approch would fail because it is going to exceed 10 bytes. This is because Solidity has lots of overhead for such contract initialization and function declaration. We want to implement a minimal contract using only opcodes.

Returning 42 is equivalent to the following opcode sequence:

```
// The "storing into memory" part
PUSH1 0x2a // [42]
PUSH1 0x00 // [0, 42]
MSTORE // mstore(0, 42) -> store the number 42 starting from memory offset 0

// The "returning" part
PUSH1 0x20 // [32]
PUSH1 0x00 // [0, 32]
RETURN // return(0, 32) -> return 32 bytes starting from memory offset 0
```

You can lookup the usage of each opcode at [evm.codes](https://www.evm.codes). At [EVM Playground](https://www.evm.codes/playground), we can compile the mnemonic we just wrote into bytecode squence. The result is:

```
602a60005260206000f3
```

This is just 10 bytes so we are good to go.

The bytecode sequence above is our **"runtime code"**. Recall that contract creation is made of two parts:

```
creation code + runtime code
```

The bytecodes for these two parts are concatenated together. When a transaction is sent to the zero address, the **"creation code"** is run until a `STOP` or `RETURN` is encountered. At that moment the contract address is set and only runtime code is left on the callstack, so we are ready to go.

### Step 2: creation code

Now we have runtime code, and we should be constructing the creation code. The idea is similar: we shall store the runtime code bytecode sequence into memory, then return it. Again, the creation code will contain the "storing into memory" part and the "returning" part.

Here is the caveat: when returning the runtime code, we have to start from memory offset 32 - 10 = 22 instead of offset 0. This is because the runtime code is not a number and we can't append any `0x00` to its left. Recall that `0x00` is the opcode for `STOP`, which is something that we should avoid. Since the runtime code is 10-byte long, it starts from memory offset 22:

```
// The "storing into memory" part
PUSH10 0x602a60005260206000f3 // [0x602a60005260206000f3]
PUSH1 0x00 // [0, 0x602a60005260206000f3]
MSTORE // mstore(0, 0x602a60005260206000f3) -> store the runtime code 0x602a60005260206000f3 starting from memory offset 0

// The "returning" part
PUSH1 0x0a // [10]
PUSH1 0x16 // [22, 10]
RETURN // return(22, 10) -> return 10 bytes starting from memory offset 22
```

Go back to EVM Playground and compile it:

```
69602a60005260206000f3600052600a6016f3
```

### Step 3: factory contract

In the very last step, we are going to deploy the bytecode we generated in step 2. This can be done with a "factory contract".

The factory contract uses `CREATE` to deploy the creation code. `CREATE` takes 3 inputs:

1. `value`: value in wei to send to the new account.
2. `offset`: byte offset in the memory in bytes, the initialisation code for the new account.
3. `size`: byte size to copy (size of the initialisation code).

Here is the factory contract:

```solidity
contract Factory {
    function deploy() external {
        // len(bytecode) = 19 = 0x13
        bytes memory bytecode = hex"69602a60005260206000f3600052600a6016f3";
        
        address addr;
        assembly {
            // create(value, offset, size)
            addr := create(0, add(bytecode, 0x20), 0x13)
        }
        
        // Verify if the contract was successfully deployed
        require(addr != address(0));
    }
}
```

Pay attention to the `create()` function call: the second parameter is `add(bytecode, 0x20)`, not `bytecode`. Here `bytecode` is a pointer to the memory location and we are getting the location 32 bytes after that pointer. But Why? It is because the datatype `bytes` is made of two parts. The first 32 bytes of it is the **length** of the byte string, and the actual value of the byte string comes after that 32 bytes. The datatype `string` works the same.

You can find an example in [Solidity doc](https://docs.soliditylang.org/en/v0.8.18/abi-spec.html):

<figure><img src="https://223316867-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MWVtlSxURaW2QQu6RU5%2Fuploads%2Fa1JUqJ6oN1FlqEzWQJmj%2FHello%20world%20ABI%20encoding%20example.png?alt=media&#x26;token=8a88a1c1-66ee-4da1-8762-9f83fa7cccc3" alt=""><figcaption><p>"Hello, world!" byte string ABI encoding example</p></figcaption></figure>

In the final version of our solution contract, we make a few changes to fit the context of this challenge:

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract MagicNumberHack {
    constructor(MagicNum challenge) {
        // len(bytecode) = 19 = 0x13
        bytes memory bytecode = hex"69602a60005260206000f3600052600a6016f3";
        
        address addr;
        assembly {
            // create(value, offset, size)
            addr := create(0, add(bytecode, 0x20), 0x13)
        }
        
        // Verify if the contract was successfully deployed
        require(addr != address(0));

        // Interact with the challenge contract
        challenge.setSolver(addr);
    }
}

contract MagicNum {

  address public solver;

  constructor() {}

  function setSolver(address _solver) public {
    solver = _solver;
  }

  /*
    ____________/\\\_______/\\\\\\\\\_____        
     __________/\\\\\_____/\\\///////\\\___       
      ________/\\\/\\\____\///______\//\\\__      
       ______/\\\/\/\\\______________/\\\/___     
        ____/\\\/__\/\\\___________/\\\//_____    
         __/\\\\\\\\\\\\\\\\_____/\\\//________   
          _\///////////\\\//____/\\\/___________  
           ___________\/\\\_____/\\\\\\\\\\\\\\\_ 
            ___________\///_____\///////////////__
  */
}
```

## Summary

Congratulations! If you solved this level, consider yourself a Master of the Universe.

Go ahead and pierce a random object in the room with your Magnum look. Now, try to move it from afar; Your telekinesis habilities might have just started working.
