# Errors

In an ideal world, we want our programs to contain the logic necessary to handle *all cases*. X occurred? No problem, there is some code to handle X. Y occurred? Not to worry, there is also some code to handle Y. However, we do not live in an ideal world, and below are two reasons as for why this is the case:

* In certain situations, we *cannot* account for *every single case*, especially if the number of cases is of a large magnitude
* In certain situations, we *do not have a good solution* for solving a problem our program is in

Fortunately, we can utilize the concept of **errors** to help navigate the flawed world that we live in. More specifically, we can use errors to respect invariants - properties of our programs (i.e. smart contracts) that we wish to maintain throughout its lifetime.&#x20;

### Raising Errors via `require`

For this section, we refer to `Bank` which is a smart contract designed to act like a bank:

{% code lineNumbers="true" %}

```solidity
contract Bank {

    mapping(address => uint256) balances;

    function deposit() public payable {
        balances[msg.sender] += msg.value;
    }

    function withdraw(uint256 amount) public {
        (bool success, ) = address(msg.sender).call{value: amount}("");
        balances[msg.sender] -= amount;
    }

}
```

{% endcode %}

Assuming that `deposit` is *correct*, we will focus on the `withdraw` function; this function is designed to send the caller the desired amount of ether they wish to withdraw. Ideally, we want for `withdraw` to maintain the following invariants of our `Bank` contract:

* Users cannot withdraw more than what they have in the bank
* The bank successfully sends users their ether

As it currently stands, `withdraw` does not respect the invariants listed above. However, we can utilize errors to revert the execution of `withdraw` if either invariant is not respected. In particular, we will utilize the `require` keyword to maintain both invariants.

Focusing on the first invariant, we want to check that the user is not withdrawing more than what they have in the bank. In terms of pseudocode, we want the following boolean condition to hold:

```
balance of caller >= amount requested to be withdrawn
```

The `require` keyword takes a boolean condition `e`; if `e` evaluates to true, nothing happens. Otherwise, if `e` evaluates to false, the transaction reverts. Therefore, we want to incorporate the following code into our contract:

```solidity
require(balances[msg.sender] >= amount);
```

Furthermore, the `require` keyword also accepts an optional error message. Updating our code to include an error message, we have the following updated contract:

```solidity
contract Bank {

    mapping(address => uint256) balances;

    function deposit() public payable {
        balances[msg.sender] += msg.value;
    }

    function withdraw(uint256 amount) public {
        require(balances[msg.sender] >= amount, "Not enough funds!");
        (bool success, ) = address(msg.sender).call{value: amount}("");
        balances[msg.sender] -= amount;
    }

}
```

At this point, `withdraw` now respects the first invariant; but what about the second invariant? Recall from the [contract interactions](https://cs4998.cornellblockchain.org/introduction/hello-world-pt.-2/contract-interactions) section that the `success` variable in `withdraw` indicates whether if the payment of ether was successful. Therefore, we just need to check that `success` is equal to true. Updating our `Bank` smart contract one final time, we have:

```solidity
contract Bank {

    mapping(address => uint256) balances;

    function deposit() public payable {
        balances[msg.sender] += msg.value;
    }

    function withdraw(uint256 amount) public {
        require(balances[msg.sender] >= amount, "Not enough funds!");
        (bool success, ) = address(msg.sender).call{value: amount}("");
        require(success, "Sending ether failed");
        balances[msg.sender] -= amount;
    }

}
```

### `revert` and `assert`

In addition to `require`, we also have the keywords `revert` and `assert` which also allow us to raise errors in our smart contracts.

`revert` acts very similarly to `require`, except that no boolean condition is needed for `revert`. An example of this can be seen below (the error message is optional, but recommended):

```solidity
function failingFunction() public {
    revert("Failing just cause");
}
```

The last keyword we will discuss is `assert`. `assert` only takes in a boolean condition. However, what makes `assert` special is that if it is ever called by a smart contract, all the gas remaining in said transaction is utilized! Whereas for `require` and `revert` refund any remaining gas.
