Ethernaut Solutions: 18-MagicNumber

The idea we are exploring here is what is the least amount of code that a contract can contain. Here are the sources that helped me understand the basics:

https://www.youtube.com/watch?v=RxL_1AfV7N4
https://blog.openzeppelin.com/deconstructing-a-solidity-contract-part-i-introduction-832efd2d7737/

When we compile a .sol file, it creates two files: .ABI and .BIN. When we deploy a contract we have to create a transaction that has “to” field set to: <0x00…00> and the “data” field has the contents of the .BIN file. This .BIN file contains instructions that can be divided into two kinds: (1) Code that deploys a contract and (2) the contract that will be deployed. This challenge requires us to write a contract (along with its deployer code) using only 10 OPCODES or less.

Lets answer the easier question first: What is the smallest contract we can create. The most minimal form a contract can take will be just a RETURN opcode. Since in our case we need to return 42 (0x2a), we will first have to store 42 to an address in memory and then return that memory address along with the size of the data. In our case it looks like this:

PUSH1 2a
PUSH1 80
MSTORE
PUSH1 20
PUSH1 80
RETURN

Now we need to write the instructions that can deploy this contract. At a minimum the deployer needs a RETURN opcode that points to the starting address of the contract being deployed. Now to do that we need to copy the contract code to a memory address and that is accomplished through CODECOPY opcode. Putting everything together, this is how our first version looks:

PUSH1 0a
PUSH1 0c
PUSH1 00
CODECOPY
PUSH1 0a
PUSH1 00
RETURN
PUSH1 2a
PUSH1 80
MSTORE
PUSH1 20
PUSH1 80
RETURN

Our first version has 13 opcodes and this challenge requires us to limit it to 10 opcodes. Apparently hackers too can be stingy on gas. Lets revisit our deployer code. We do not need the COPYCODE opcode if we can do that via another way.

First we get our contract in the hex format:

PUSH1 2a
PUSH1 80
MSTORE
PUSH1 20
PUSH1 80
RETURN

becomes: 602a60805260806020f3

Now we simply save this value in memory and use the deployer code to return its address:

PUSH10 602a60805260806020f3
PUSH1 00
MSTORE
PUSH1 0a
PUSH1 16
RETURN

6 opcodes. Mission accomplished.