Follow

# [REDACTED]

Follow Eval
·Mar 18, 2022·

# Overview

This level introduces us to the following concept(s):

• Arithmetic underflows/overflows
• Usage of SafeMath library (and `pragma solidity ^0.8.0`)
• `unchecked` keyword in Solidity

GitHub Repository available at: github.com/0xEval/ethernaut-x-foundry

## Objective

To complete the challenge, we will need to:

• Increase your initial token supply beyond 20

## Contract Analysis

At contract creation, an initial token supply is created and is assigned to the deployer's balance (note the double `=` assignment pattern, read it from right to left)

The `transfer()` function allows the `msg.sender` to send some tokens to someone else, given he has sufficient balance.

Finally, we can inspect any address' balance using the `balanceOf()` function.

⚠️ It is important to mention that the original Ethernaut contract for this level is set to compiler version `^0.6.0`. Our modified version runs on `^0.8.10`, we will explain why this matters.

``````contract Token {

uint public totalSupply;

constructor(uint _initialSupply) {
balances[msg.sender] = totalSupply = _initialSupply;
}

function transfer(address _to, uint _value) public returns (bool) {
require(balances[msg.sender] - _value >= 0);
balances[msg.sender] -= _value;
balances[_to] += _value;
return true;
}

function balanceOf(address _owner) public view returns (uint balance) {
return balances[_owner];
}
}
``````

The contract is vulnerable to arithmetic over/underflows. Here's an excerpt from the Solidity docs:

Prior to Solidity 0.8.0, arithmetic operations would always wrap in case of under- or overflow leading to widespread use of libraries that introduce additional checks.

Since Solidity 0.8.0, all arithmetic operations revert on over- and underflow by default, thus making the use of these libraries unnecessary.

To understand what wrapping means, let's look at the following representation: Storage values boundaries for different data types in C

Say you have a variable `x` of type `unsigned int (uint)`:

• If `x = UINT_MAX` and `x = x + 1`, then `x` will cycle back to its lower bound `UINT_MIN`
• vice-versa if `x = UINT_MIN` and `x = x - 1`, then `x` will be equal to `UINT_MAX`

This is what's happening in the `Token` contract when calling the `transfer()` function!

Our custom contract has been ported to Solidity `^0.8.10`, so it won't be vulnerable. But, we surround the arithmetic logic in an `unchecked` statement, which tells the compiler not to verify anything.

Contracts deployed on earlier versions of Solidity make use of battle-tested libraries to handle this for them. The most commonly used is OpenZeppelin's SafeMath. It is useful to be accustomed to it.

# Attacking The Contract

Make sure to read through Part 0 for setup instructions.

Create the `Token.t.sol` test file in the `test/` directory that will contain the attack logic (level setup and submission is truncated for clarity):

``````function testTokenHack() public {

emit log_named_uint(
"playerContract balance",
);

emit log_named_uint(
"playerContract balance",
Run the attack using the `forge test` subcommand: 